Když jsem nedávno psal nějakou třídičku v PHP tak jsem narazil na dost častou záležitost, použil jsem statickou proměnnou na definování implicitní hodnoty a další nestatickou proměnnou, která umožňuje nastavit danou vlastnost pokud od třídy dědíme. Vypadá to asi nějak takto.
class MyClass { /** variable with default value */ private static $_defaultVariable; /** variable for an usage with an inheritance */ private $_variable; }
Předpokládané použití je takové, že statická implicitní vlastnost bude v aplikaci, která třídu používá dostupná tak nějak "automaticky", pokud budeme vytvářet potomky třídy, tak si jí podle potřeby můžeme dynamicky modifikovat. Jak teď ale na to implicitní inicializaci. V PHP neexistuje nějaký jasný prostředek, jak inicializovat statické proměnné tříd - statické konstruktory. Máme v podstatě dvě možnosti, jak to řešit. Každopádně do třídy umístíme statickou metodu initialize
, která bude představovat náš statický konstruktor.
class MyClass { /** variable with default value */ private static $_defaultVariable; /** variable for an usage with an inheritance */ private $_variable; public static initialize() { ........ self::$_defaultVariable = ..... } }
Máme asi následující možnosti
- Metodu
initialize
zavolat globálně v souboru se třídou, tím se její kód provede po natažení souboru s třídou. - Nějak to ošetřit autoloaderem tříd, po načtení třídy bude vždy autoloader volat metodu
initialize
, pokud ji třída obsahuje.
První případ by asi vypadal nějak takto
//file MyClass.php class MyClass { /** varible with default value */ private static $_defaultVariable; /** variable for an usage with an inheritance */ private $_variable; public static initialize() { ........ self::$_defaultVariable = ..... } } MyClass::initialize();
V druhém případě by modifikovaný autoloader mohl vypadat asi nějak takto
class MyLoader extends LibLoader { public static function loadClass($className) { const INITIALIZER_NAME = "initialize"; /* * creates $filename from $className... */ include_once $filename; // a reference to the static constructor's operation $staticConstructorReference = array($className, self::INITIALIZER_NAME); // if the static constructor was declared properly, call this one if (is_callable($staticConstructorReference)) { call_user_func($staticConstructorReference); } }
Těžko říci, co je lepší. Nejlepší by bylo, kdyby statické konstruktory byly už přímo v PHP, jednodušší je určitě první varianta, druhá je zase asi tak nějak čistší a systémovější. Ještě je tu ale třetí možnost, která se používá také docela často, možná i nejčastěji, je to vidět zejména v aplikacích založených na nějakých frameworcích, inicializace statických proměnných se se nechá na aplikaci a provede se většinou v bootstrapu aplikace, při natahování konfigurací apod.
Komentáře (5)
Mě teda přijde čistší ten první způsob, je při něm jasné, že nahrání třídy jakýmkoli způsobem == initialize. Druhá možnost přidává závislost té třídy na svém autoloaderu, čímž dost omezuje její znovupoužití v jiných projektech.
Případně může getter vracet referenci, je-li to vhodné (většinou asi ne)...Ale upřímně se mi nelíbí ani jedna z nastíněných možností.
Ještě je možné nepřistupovat k hodnotě přes vlastnost. Nadefinovat getter a inicializaci dát do něj:
První dvě možnosti vyžadovali poznámku v dokumentaci, tady je vše jasné ze samotného API. Výhodou oproti statickým konstruktorům a důvod pro použití i v jazycích, které je mají, může být lazy-loading. Objekt se inicializuje až v momentě, kdy je potřeba.
Co takhle volat v každé metodě, kde je to potřeba, nějaké self::initOnce(), které by poprvé vše inicializovalo a pak nedělalo nic?
[1] ten první způsob není tak úplně odolný proti include/require, když to nebude include_once, tak se ta inicializace může volat vícekrát, ale to zase až tak vadit to nemusí
ten getter vypadá jako že by to šlo, díky
[2] to my nepříjde jako úplně šťastné, na to se bude zapomínat, ten statický getter bude lepší.
[3] Když to nebude include_once/require_once, tak především vznikne fatální chyba "Cannot redeclare class".
[4] no to je pravda
nakonec bych ten statický konstruktor v PHP stejně docela přivítal :-)
Komentáře jsou uzavřeny.