Weils so schön ist: Ein weiteres mal Zend_Loader_Autoloader. Ich hoffe damit endgültig mal (zumindest im deutschsprachigen Raum) mit den ewigen Diskussionen über "merkwürdiges Verhalten beim Laden von Klassen" abschließen zu können.

02.04.2010: Kleines (sprachliches) Update, su

Grundlage

Die Grundlage ist natürlich PHP selbst. PHP bietet dazu zwei Mechanismen:

  1. Eine selbst definierte Funktione __autoload($class) oder
  2. spl_autoload($lcass)

Die zweite Variante greift, sobald spl_autoload_register() einmal aufgerufen wird und sie ersetzt __autoload() vollständig. Genau das macht Zend_Loader_Autoloader beim ersten Aufruf von getInstance().

spl_autoload() nutzt einen Stack [1], man kann also beliebig viele eigene Loader registrieren, die von PHP selbst zum Laden von Klassen aufgerufen werden. Insbesondere bedeutet das, dass man problemlos auch Autoloader fremder Hersteller (zB Doctrine) ohne Anpassung weiter verwenden kann!

.

Zend_Loader_Autoloader kümmert sich pauschal nur um Klassen, die mit einem String beginnen, die er kennt (Prefix, Namespace). Wie man weitere Prefix bekannt macht, sehen wir gleich.

Zend_Loader_Autoloader: für die Library

Zend_Loader_Autoloader besitzt intern schonmal einen eigenen Loader. Dieser ist vorwiegend zu Laden von Library-Klassen gedacht!. Er mappt dabei einfach den Klassenbezeicher (zB) Zend_Controller_Front gegen den Dateinamen Zend/Controller/Front.php und sucht selbigen im include_path. Konkret: Die Library-Ordner (hier "Zend") müssen sich in einem Ordner befinden, der in einen der im include_path angegebenen Pfade befindet!

Damit Autoloader nun auch andere Klassenbezeichner, als nur die mit dem "Zend"-Prefix berücksichtigt, macht man den Prefix mit registerNamespace() bekannt.

Zend_Loader_Autoloader_Resource: Für Anwendungs-Klassen

Autloader lässt sich sehr leicht um weiter, nicht dem obigen Standard folgenden Loadern erweitern, indem ihn Objekt, die Autoloader_Interface implementieren, oder Callbacks übergibt, dazu aber im Handbuch mehr [2], denn für gewöhnlich interessiert das erstmal wenig.

Eine Implementierung ist Zend_Loader_Autoloader_Resource. Dieser ["der Resource-Loader", Anm. des Authors] ist zum Laden der Modul-Klassen gedacht! Dazu wird zunächst ein Basis-Pfad und wiederum ein Prefix übergeben, weiterhin erhält er ein oder mehrere Typ-Namespaces plus dazugehörige Ordner. Das Mapping erfolgt nicht mehr einfach Klassenbezeichner-zu-Dateiname, sondern nur noch der Bezeichner ohne Prefix plus Typ-Namespace wird gegen den Basispfad plus Typ-Ornder gemappt:
[code]Prefix: Blogmodule
Basispfad: /path/to/application/modules/blog

# Typ-Mappings:
Model => models/
Model_DbTable => models/DbTable/

# Beispiel
Blogmodule_Model_My_Class => /path/to/application/modules/blog/models/My/Class.php[/code]Bei Instanzierung registriert sich der dieser Loader selbstständig beim Zend_Loader_Autoloader-Objekt, ein manuelles pushAutoloader() ist nicht notwendig.

Das, was man jetzt gehört hat, kann man schon fast wieder vergessen, denn Zend_Application_Module_Autoloader ist eine Erweiterung von Autoloader_Resource, ergänzt selbige durch typische Modul-Klassentypen und deren typische Verzeichnisse [3] und es wird für jedes Modul automatisch erstellt, welches eine Module-Bootstrap besitzt und wenn das Modules-Resource-Plugin von Zend_Application aktiviert ist. Für letzteres genügt ein "resources.modules[] =" in der application.ini.

Plugins Laden

Einige Komponenten, darunter Zend_Controller_Action_HelperBroker für die Action-Helper und Zend_View_Abstract für View-Helper, nutzen Zend_Loader_PluginLoader, der ähnlich funktioniert, wie der eben erwähnte Resource-Loader, allerdings selbst kein Autoloader ist. Er dient dazu bei einem verkürzten Klassenbezeichner [4] eine Klasse zu finden, indem er einfach alle registrierten Prefix-zu-Pfad-Varianten durchprobiert.

Will man hier etwas hinzufügen, kommt man an den Plugin-Loader für gewöhnlich mit der getPluginloader() auf das entsprechende Objekt, zB View, oder HelperBroker ran. Aber auch das ist (ähnlich wie für Application_Module_Autoloader) oft überflüssig. Das FrontController- bzw das View-Resource-Plugin [5] für Zend_Application nehmen einen diese Arbeit (mal wieder) über die application.ini ab:
[code]resources.view.helperPath.My_Prefix = /path/to/my/viewhelpers
resources.frontcontroller.actionhelperpaths.My_Prefix = /path/to/my/actionhelpers[/code]

Ein kurzer Hinweis an dieser Stelle: Wenn Zend_Layout trotz gegebener Helferpfade eigene Helfer nicht findet, kann man prüfen, ob in application.ini die View-Resource vor der Layout-Resource definiert wird. Ist es anders herum, kann es passieren, dass der View-Renderer und Layout zwei verschiedene Views verwenden und somit Einstellungen an Einem am Anderen vorbei gehen.


[1]
Eigentlich eine Queue
[2]
Zend_Loader_Autoloader_Interface
[3]
Quelltext von Zend_Application_Module_Autoloader
[4]
Dem Bezeichner fehler der Prefix und er somit nicht eindeutigt.
[5]
Dies ist nicht bei Zend_Application dokumentiert, aber als Faustformel für die meisten Resource-Plugins: Was als set*-Methode existiert, lässt sich auch per application.ini setzen. In konkreten Fall ist es Zend_View_Abstract::setHelperPath() bzw für die Action-Helper schaut man einfach mal in den Sourcecode zu Zend_Application_Resource_Frontcontroller.
  1. 02.04.2010: Auf Wunsch eines einzelnen, anonymen Querulanten sprachlich hier und da rumgedoktort ;)