Autoload
Weniger ist mehr
Schon seit einiger Zeit versuche ich nach Möglichkeit keine requires oder includes in meinem Code zu verwenden. Dies hat einen praktischen Grund – ich habe schlicht keine Lust, diese Angaben zu pflegen – und einen e
her „philosophischen“: Eine Klasse soll sich in der Hauptsache mit ihrem „Thema“ beschäftigen und möglichst wenig über die Welt da draußen, ihre Umgebung, wissen müssen.
Mitunter ist ein gewisser Kontakt zur Aussenwelt aber doch hilfreich, insbesondere wenn ein Objekt mit anderen kommunizieren muss, um seine Aufgaben zu erledigen.
Wird nach einer Klasse oder einem Interface verlangt, das bislang noch nicht eingebunden wurde, kommt der Autoload-Mechanismus von PHP5 ins Spiel. PHP versucht durch den Aufruf der magischen Methode __autoload() doch noch an das Benötigte zu kommen. Durch Überschreiben von __autoload() lassen sich mit wenigen Zeilen sämtliche require()- und include()-Aufrufe einsparen.
Es kann nur einen geben
Da dieses Feature sehr nützlich ist, ist es auch recht bekannt. Schade nur, wenn man neben seinem eigenem Autoload-Mechanismus auch noch weitere (fremde) Komponenten einbinden will, die sich ebenfalls auf __autoload() verlassen. PHP quittiert eine mehrfache Deklaration natürlich mit einem fatalem Fehler.
SPL
Abhilfe schafft hier das weniger bekannte spl_autoload_register() – einer ab PHP 5.1.2 verfügbaren Funktion aus der bereits erwähnten Standard PHP Library. Ob diese Funktion wirklich weniger bekannt ist, kann ich natürlich nicht sagen. In unserer Entwicklungsabteilung erfreute sie sich jedenfalls erst in diesem Jahr größerer Bekanntheit.
Die Lösung, die SPL mitbringt, klingt einfach und ist sie auch vom Handling her: Mit spl_autoload_register() können beliebig benannte Autoload-Funktionen registiert, d.h. auf einen Stack gelegt werden. Bei dem Versuch fehlende Klassen oder Interfaces nachzuladen, ruft PHP nun nicht mehr die – jetzt deaktivierte – globale __autoload()-Methode auf, sondern arbeitet nach dem FIFO-Prinzip den spl-autoload-Stapel ab.
Hatte man bereits eine __autoload()-Metthode geschrieben, so kann diese trotzdem zum Einsatz kommen, indem sie ebenfalls registriert wird. Es lassen sich übrigens nicht nur globale Funktionen auf den Stapel legen, sondern alles was sich aufrufen läßt: globale Funktionen, statische Methoden und Methoden instanziierter Objekte:
// globale Funktion registrieren function neueAutoloadFunktion($class) { include_once($class . ".php"); } spl_autoload_register("neueAutoloadFunktion"); // statische Methode registrieren // z.B. zur Einbindung von ezComponents class TestKlasse { public static function neueStatischeAutoloadMethode($class) { include_once($class . ".php"); } } spl_autoload_register(array("TestKlasse", "neueStatischeAutoloadMethode")); // Methode einer Objekt-Instanz registrieren class WeitereTestKlasse { public function neueAutoloadMethode($class) { include_once($class . ".php"); } } $obj = new WeitereTestKlasse(); spl_autoload_register(array($obj, "neueAutoloadMethode")); // Um den Ueberblick zu behalten: Autoload-Stack anzeigen print(""); print_r(spl_autoload_functions()); print("");
$test = new NichtDeklarierteKlasse();?>
Die Doku: http://www.php.net/manual/de/function.spl-autoload-register.php
Praktische Anwendung bei ezComponents: http://ezcomponents.org/docs/installzp8497586rq