1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
|
<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 24249 -->
<!-- Reviewed: no -->
<sect1 id="zend.loader.pluginloader">
<title>Plugins laden</title>
<para>
Eine Anzahl von Zend Framework Komponenten ist steckbar, und erlaubt es Funktionen dynamisch
zu laden durch die Angabe eines Klassenpräfixes und einem Pfad zu den Klassendaten die nicht
notwendigerweise im <property>include_path</property> sind, oder nicht notwendigerweise den
traditionellen Namenskonventionen folgen. <classname>Zend_Loader_PluginLoader</classname>
bietet übliche Funktionalitäten für diesen Prozess.
</para>
<para>
Die grundsätzliche Verwendung vom <classname>PluginLoader</classname> folgt den
Namenskonventionen vom Zend Framework mit einer Klasse pro Datei, der Verwendung von
Unterstrichen als Verzeichnistrenner bei der Auflösung von Pfaden. Es erlaubt die Übergabe
eines optionalen Klasenpräfixes der vorangestellt wird, wenn eine bestimmte Pluginklasse
geladen wird. Zusätzlich können Pfade in LIFO Reihenfolge durchsucht werden. Die LIFO Suche
und der Klassen Präfix erlaubt es für die Plugins Namensräumen zu definieren, und auf diese
Weise Plugins zu überladen die vorher registriert wurden.
</para>
<sect2 id="zend.loader.pluginloader.usage">
<title>Grundsätzliche Verwendung</title>
<para>
Nehmen wir zuerst die folgende Verzeichnis Struktur und Klassendateien an, und dass das
oberste Verzeichnis und das Library Verzeichnis im include_path sind:
</para>
<programlisting language="txt"><![CDATA[
application/
modules/
foo/
views/
helpers/
FormLabel.php
FormSubmit.php
bar/
views/
helpers/
FormSubmit.php
library/
Zend/
View/
Helper/
FormLabel.php
FormSubmit.php
FormText.php
]]></programlisting>
<para>
Jetzt wird ein Plugin Lader erstellt um die verschiedenen vorhandenene View Helfer
Repositories anzusprechen:
</para>
<programlisting language="php"><![CDATA[
$loader = new Zend_Loader_PluginLoader();
$loader->addPrefixPath('Zend_View_Helper', 'Zend/View/Helper/')
->addPrefixPath('Foo_View_Helper',
'application/modules/foo/views/helpers')
->addPrefixPath('Bar_View_Helper',
'application/modules/bar/views/helpers');
]]></programlisting>
<para>
Anschließend kann ein gegebener View Helfer geladen werden indem nur der Teil des
Klassennamens verwendet wird der dem Präfix folgt wie er definiert wurde als die Pfade
hinzugefügt wurden:
</para>
<programlisting language="php"><![CDATA[
// lädt den 'FormText' Helfer:
$formTextClass = $loader->load('FormText'); // 'Zend_View_Helper_FormText';
// lädt den 'FormLabel' Helfer:
$formLabelClass = $loader->load('FormLabel'); // 'Foo_View_Helper_FormLabel'
// lädt den 'FormSubmit' Helfer:
$formSubmitClass = $loader->load('FormSubmit'); // 'Bar_View_Helper_FormSubmit'
]]></programlisting>
<para>
Sobald die Klasse geladen wurde, kann diese Instanziiert werden.
</para>
<note>
<title>Mehrere Pfade können für einen gegebenen Präfix registriert werden</title>
<para>
In einigen Fällen kann es gewünscht sein den gleichen Präfix für mehrere Pfade zu
verwenden. <classname>Zend_Loader_PluginLoader</classname> registriert aktuell ein
Array von Pfaden für jeden gegebenen Präfix; der zuletzt resistrierte wird als erste
geprüft. Das ist teilweise nützlich wenn Inkubator Komponenten verwendet werden.
</para>
</note>
<note>
<para>
Optional kann ein Array von Präfix / Pfad Paaren angegeben werden (oder Präfix /
Pfade -- Plural, Pfade sind erlaubt) und als Parameter dem Kontruktor übergeben
werden:
</para>
<programlisting language="php"><![CDATA[
$loader = new Zend_Loader_PluginLoader(array(
'Zend_View_Helper' => 'Zend/View/Helper/',
'Foo_View_Helper' => 'application/modules/foo/views/helpers',
'Bar_View_Helper' => 'application/modules/bar/views/helpers'
));
]]></programlisting>
</note>
<para>
<classname>Zend_Loader_PluginLoader</classname> erlaubt es auch optional Plugins über
Plugin-fähige Objekte zu teilen, ohne das eine Singleton Instanz verwendet werden muß.
Das wird durch eine statische Registrierung ermöglicht. Der Name des Registry muß bei
der Instanziierung als zweiter Parameter an den Konstruktor übergeben werden:
</para>
<programlisting language="php"><![CDATA[
// Speichere Plugins in der statischen Registry 'foobar':
$loader = new Zend_Loader_PluginLoader(array(), 'foobar');
]]></programlisting>
<para>
Andere Komponenten die den <classname>PluginLoader</classname> instanziieren un den
gleichen Registry Namen verwenden haben dann Zugriff auf bereits geladene Pfade und
Plugins.
</para>
</sect2>
<sect2 id="zend.loader.pluginloader.paths">
<title>Plugin Pfade manipulieren</title>
<para>
Das Beispiel der vorherigen Sektion zeigt wie Pfade zu einem Plugin Loader hinzugefügt
werden können. Aber was kann getan werden um herauszufinden ob ein Pfad bereits geladen,
entfernt oder anderes wurde?
</para>
<itemizedlist>
<listitem>
<para>
<methodname>getPaths($prefix = null)</methodname> gibt alle Pfade als Präfix /
Pfad Paare zurück wenn kein <varname>$prefix</varname> angegeben wurde, oder nur
die registrierten Pfade für einen gegebenen Präfix wenn ein
<varname>$prefix</varname> vorhanden ist.
</para>
</listitem>
<listitem>
<para>
<methodname>clearPaths($prefix = null)</methodname> löscht standardmäßig alle
registrierten Pfade, oder nur die mit einem gegebenen Präfix assoziierten, wenn
<varname>$prefix</varname> angegeben wurde und dieser im Stack vorhanden ist.
</para>
</listitem>
<listitem>
<para>
<methodname>removePrefixPath($prefix, $path = null)</methodname> erlaubt das
selektive löschen eines speziellen Pfades der mit einem gegebenen Präfix
assoziiert ist. Wenn <varname>$path</varname> nicht angegeben wurde, werden alle
Pfade für diesen Präfix entfernt. Wenn <varname>$path</varname> angegeben wurde
und dieser für den Präfix existiert, dann wird nur dieser Pfad entfernt.
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="zend.loader.pluginloader.checks">
<title>Testen auf Plugins und Klassennamen erhalten</title>
<para>
Hier und da soll einfach eruiert werden ob eine Pluginklasse bereits geladen wurde bevor
eine Aktion ausgeführt wird. <methodname>isLoaded()</methodname> nimmt einen Pluginnamen
und gibt den Status zurück.
</para>
<para>
Ein anderer üblicher Fall für das <classname>PluginLoader</classname> ist das eruieren
des voll qualifizierten Plugin Klassennamens von geladenen Klassen;
<methodname>getClassName()</methodname> bietet diese Funktionalität. Typischerweise wird
dieses in Verbindung mit <methodname>isLoaded()</methodname> verwendet:
</para>
<programlisting language="php"><![CDATA[
if ($loader->isLoaded('Adapter')) {
$class = $loader->getClassName('Adapter');
$adapter = call_user_func(array($class, 'getInstance'));
}
]]></programlisting>
</sect2>
<sect2 id="zend.loader.pluginloader.performance">
<title>Bessere Performance für Plugins erhalten</title>
<para>
Das Laden von Plugins kann eine teure Operation sein. Im Innersten muß es durch jeden
Präfix springen, dann durch jeden Pfad dieses Präfixes, solange bis es eine passende
Datei findet -- und welche die erwartete Klasse definiert. In Fällen wo die Datei
existiert aber die Klasse nicht definiert ist, wird ein Fehler auf dem
<acronym>PHP</acronym> Fehlerstack hinzugefügt, was auch eine teure Operation ist. Die
Frage die sich stellt lautet also: Wie kann man die Flexibilität der Plugins behalten
und auch die Performance sicherstellen?
</para>
<para>
<classname>Zend_Loader_PluginLoader</classname> bietet ein optional einschaltbares
Feature für genau diese Situation, einen integrierten Cache für die Klassendateien. Wenn
er aktiviert wird, erstellt er eine Datei die alle erfolgreichen Includes enthält welche
dann von der Bootstrap Datei aus aufgerufen werden kann. Durch Verwendung dieser
Strategie, kann die Performance für Produktive Server sehr stark verbessert werden.
</para>
<example id="zend.loader.pluginloader.performance.example">
<title>Verwendung des integrierten Klassendatei Caches des PluginLoaders</title>
<para>
Um den integrierten Klassendatei Cache zu verwenden muß einfach der folgende Code in
die Bootstrap Datei eingefügt werden:
</para>
<programlisting language="php"><![CDATA[
$classFileIncCache = APPLICATION_PATH . '/../data/pluginLoaderCache.php';
if (file_exists($classFileIncCache)) {
include_once $classFileIncCache;
}
Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);
]]></programlisting>
<para>
Natürlich, veriiert der Pfad und der Dateiname basieren auf den eigenen
Bedürfnissen. Dieser Code sollte so früh wie möglich vorhanden sein um
sicherzustellen das Plugin-basierende Komponenten davon Verwendung machen können.
</para>
<para>
Wärend der Entwicklung kann es gewünscht sein den Cache auszuschalten. Eine Methode
um das zu tun ist die Verwendung eines Konfigurationsschlüsses um festzustellen ob
der PluginLoader cachen soll oder nicht.
</para>
<programlisting language="php"><![CDATA[
$classFileIncCache = APPLICATION_PATH . '/../data/pluginLoaderCache.php';
if (file_exists($classFileIncCache)) {
include_once $classFileIncCache;
}
if ($config->enablePluginLoaderCache) {
Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);
}
]]></programlisting>
<para>
Diese Technik erlaubt es die Änderungen in der Konfigurationsdatei zu belassen und
nicht im Code.
</para>
</example>
</sect2>
</sect1>
|