Přeskočit na hlavní obsah

PHP a Zend Framework autoloading

Úvod

V příspěvku se zmíním o způsobu a správě „importů“ (tzv. autoloading) php souborů v samotném PHP a poté se dozvíme, jak autoloading php souborů řeší Zend Framework.

Autoloading v PHP

Základem při psaní aplikací v PHP je nutné si uvědomit, jak funguje tzv. autoloading php souborů. V PHP neexistují importy jako je známe např. z Java. Když například potřebujete konstruhovat třídu jejíž definice je v jiném souboru – je nutné si tento soubor za pomocí konstrukce require nebo require_once(include, include_once) “naimportovat“ do svého souboru (předpokladem, je že soubory jsou umístěné na include_path). Dalším řešením je překrýt funkci autoload.

Správa importů v PHP

Správa “importů” souborů v php mi přijde neštastná. Jedná se do jisté míry o problém, alespoň pro mne – jsem vývojářem v Java, kde tento mechanismus je zajištován za pomocí Eclipse IDE, který se postará o seznam všech tříd, které v rámci souborů používám – jinak řečeno se o tuto oblast při vývoji vůbec nestarám.

Jak "importovat" v PHP soubory

Jak vlastně vývojář v PHP zajistí import souborů? Existují dvě cesty, které jsem již představil výše:

  1. použití nativních funkcí PHP (include, include_once,require nebo require_once),
  2. překrýt funkci autoload (od verse PHP 5+)

První způsob je použitelný, pakliže je aplikace jednoduchá a manuální správa importů je víceméně triviální. Import je řešen uvedením “filepath” k požadovaného souboru ve formě stringu a předání ji výše uvedeným funkcím (např. include(“cesta/k/souboru.php”)) . Druhý způsob je již elegantnějším způsobem, jak zajistit import souborů automaticky.

Jak funguje mechanismus importů v PHP

PHP se snaží soubor najít na základě filepath uvedenou v parametru funkce, v případě, že není cesta uvedena, snaží se najít soubor na základě definované include_path. Když soubor není nalezen ani na include_path, pak se jej snaží najít v tom samém adresáři, kde se naléza soubor, který tento import souboru “zavolal”. Když jej nenalézá mechanismus generuje hlášení – v případě include(_once) WARNING, v případě require(_once) generuje FATAL_ERROR – přehled popisu chyb naleznete v článku Chybová hlášení v PHP.

Autoloading v Zend Framework

Autoloading má na starosti implementace Zend_Loader. Autoloading je úzce spjatý s adresářovou strukturou projektu. Vše vychází z předpokladu – název třídy implementované v souboru je zároveň předpisem jeho “package-path”, kde jej autoloader nalezne. Nicméně umísťění souboru na include_path a následný “import” za pomocí nativních funkcí php je stále možný. ZF vás v tomto ohledu vůbec neomezuje.

Příklad ukazuje jak zapsat název třídy, která bude umístěna v :

%APACHE_HOME%/htdocs/zendapp/testdir/Person.php

K oddělení adresářů slouží podtržítko – dle oficiálního zdroje (Zend Framework dokumentace) je nápad převzatý od PEAR, ale nedělám si ambice zde tuto skutečnost nějak komentovat. Zápis třídy umístěné v adresářové sktruktuře vypadá následovně:

class Zendapp_Testdir_Person {
   //nazev tridy je plna package path, 
   //Zendapp je namespace, ale to vysvetlim pozdeji
 }

Je zřejmé, že název tříd hraje klíčovou roli v autoloadingu v rámci ZF projektu. Autoloading je víceměné automatická záležitost. Je potřeba nakonfigurovat prostředí – registrace modulu a namespace modulu. Dále namapování adresářů umístěné v namespace modulu. Když toto splníte – autoloading v rámci ZF projektu je k Vaším službám připravena. Existuje však způsob jak si autoloading „upravit“. ZF vývojáři jsou v tomto ohledu velmi praktičtí a nabízejí velmi obecné řešení, které je snadno překrytelné vlastní implementací.

V oficiální dokumentaci je uvedeno, že cíle a návrh autoloadingu jsou následující:

  1. dohledání třídy dle namespace – což je prefix, který deklaruje adresář, kde nalezne adresářovou strukturu vašeho projektu a třídy v něm uložené
  2. automatický autoloading (tzv. fallback autoloading), což zjednodušeně znamená, že definujeme pouze prefix namespace, ale nedeklarujete, do jakého adresáře je namapován
  3. je možné konfigurací „potlačit“ (supress) chyby
  4. překrýt ZF autoloading mechanismus svou implementací

Poznámka k bodu dva – fallback autoloading. Jedná se o to, že není nutné konfigurovat (mapovat) strukturu projektu. Pouze zaregistrujete příslušný prefix namespace, dle kterého se autoloader bude snažit dohledat vaše třídy. Jednoduché, ale ZF dokumentace hovoří jasně – není to doporučováno. Jak tedy tento způsob autoloadingu nastavit – v souboru %APACHE_HOME%/htdocs/zendapp/index.php:

require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
$loader->setFallbackAutoloader(true);

Existuje však i cesta, jak se také vyhnout konfiguraci a říct autoloaderu, že vaše třídy budou např. začínat prefixy Admin, Salary. A ať si je najde sám. Sice to není ideál, ale lepší než používat výše uvedené nastavení autoloadingu:

require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace(array('Admin_', 'Blog_'));

Případně pro nastudování případných úskalí „bezkonfiguračního autoloadingu“ se mrkněte přímo do dokumentace.

Komentáře

Populární příspěvky z tohoto blogu

XAMPP - problémy s Apache (ServerRoot must be a valid directory, make_sock: could not bind to address)

O instalaci a příspěvek  o spuštění Apache  a MySQL serveru jsem již psal na svém blogu. Při nedávné instalaci, kterou jsem pojal jako kata cvičení, abych nevyšel z formy jsem narazil na problémy, které jsem již řešil a považuji je, za standard a mnohým ušetří to "pátrání". Výčet nemusí být konečný (pakliže se budu dopouštět takových chyb) : ServerRoot must be a valid directory Hlášení - httpd.exe: Syntax error on line xx /path/to/your/apache/conf : ServerRoot must be a valid directory ( %XAMPP_HOME%/apache/logs/error.log ) Popis - máte nekonzistentí namapování adresářové struktury pro server Apache. Ověřte si, co je zapsáno v direktivě ServerRoot v konfiguračním souboru ( %XAMPP_HOME%/apache/cont/httpd.conf)  měla by tam být buď absolutní v lepším případě relativní cesta k adresáři %XAMPP_HOME%/apache . Řešení - nejjednoduší je zapsat absolutní cestu k adresáři Apache serveru. Někdy je pouze znovu-namapovat adresářovou strukturu za pomocí konsole - s...

Zend_Tool - Cannot redeclare class Zend_Loader

V mém případě, když jsem zadal následující příkaz: zf create module admin V konsoli se objevila následujicí hláška Cannot redeclare class Zend_Loader in path/to/library/Zend/Loader on line 31 Řešení je jednochuché - Nakopírujte soubory zf.bat a zf.php z adresáře %ZEND_FRAMEWORK_DIR%/bin do adresáře %PHP_HOME% . V případě, že chcete vědět více – mkrněte na oficiální dokumentaci Zend_Tool .

How to override (hack) location directories eg. Model in Zend Framework projects

Content At beginning Use Case Standart directory layout Specific directory layout Solvetion Summary At beginning This approach is bad but it is trivial and works. First I thought about a way how to inject/override by my implementation but if I stood before "I need only change location where objects will be generated..." Use Case For example - your project's 'models' directory has different structure and you must remove each generated model's php file to your specific directory. Standart directory layout If you use command "zf create model ItemModel" . ItemModel file will be generated by default in directory 'models' . ----models |--DbTable |--ItemModel.php Specific directory layout We want to generate model class in subdirectory 'Domain' . That's all. ----models |--DbTable |--Domain |--ItemModel.php Solvetion We must find directory '%ZF_HOME%\library\Zend\Tool\Project\Context\Zf\' . T...