[MANUAL] English:
[zend.git] / documentation / manual / en / module_specs / Zend_Loader-PluginLoader.xml
blobe14e8b165db5d61ec9f3d09529d8c4a4cc87fa91
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <sect1 id="zend.loader.pluginloader">
4     <title>Loading Plugins</title>
6     <para>
7         A number of Zend Framework components are pluggable, and allow loading
8         of dynamic functionality by specifying a class prefix and path to class
9         files that are not necessarily on the <code>include_path</code> or do
10         not necessarily follow traditional naming conventions.
11         <classname>Zend_Loader_PluginLoader</classname> provides common functionality for
12         this process.
13     </para>
15     <para>
16         The basic usage of the <code>PluginLoader</code> follows Zend Framework
17         naming conventions of one class per file, using the underscore as a
18         directory separator when resolving paths. It allows passing an optional
19         class prefix to prepend when determining if a particular plugin class is
20         loaded. Additionally, paths are searched in LIFO order. Due to the LIFO
21         search and the class prefixes, this allows you to define namespaces for your
22         plugins, and thus override plugins from paths registered earlier.
23     </para>
25     <sect2 id="zend.loader.pluginloader.usage">
26         <title>Basic Use Case</title>
28         <para>
29             First, let's assume the following directory structure and class
30             files, and that the top level directory and library directory are on
31             the include_path:
32         </para>
34         <programlisting language="txt"><![CDATA[
35 application/
36     modules/
37         foo/
38             views/
39                 helpers/
40                     FormLabel.php
41                     FormSubmit.php
42         bar/
43             views/
44                 helpers/
45                     FormSubmit.php
46 library/
47     Zend/
48         View/
49             Helper/
50                 FormLabel.php
51                 FormSubmit.php
52                 FormText.php
53 ]]></programlisting>
55         <para>
56             Now, let's create a plugin loader to address the various view
57             helper repositories available:
58         </para>
60         <programlisting language="php"><![CDATA[
61 $loader = new Zend_Loader_PluginLoader();
62 $loader->addPrefixPath('Zend_View_Helper', 'Zend/View/Helper/')
63        ->addPrefixPath('Foo_View_Helper',
64                        'application/modules/foo/views/helpers')
65        ->addPrefixPath('Bar_View_Helper',
66                        'application/modules/bar/views/helpers');
67 ]]></programlisting>
69         <para>
70             We can then load a given view helper using just the portion of the
71             class name following the prefixes as defined when adding the paths:
72         </para>
74         <programlisting language="php"><![CDATA[
75 // load 'FormText' helper:
76 $formTextClass = $loader->load('FormText'); // 'Zend_View_Helper_FormText';
78 // load 'FormLabel' helper:
79 $formLabelClass = $loader->load('FormLabel'); // 'Foo_View_Helper_FormLabel'
81 // load 'FormSubmit' helper:
82 $formSubmitClass = $loader->load('FormSubmit'); // 'Bar_View_Helper_FormSubmit'
83 ]]></programlisting>
85         <para>
86             Once the class is loaded, we can now instantiate it.
87         </para>
89         <note>
90             <para>
91                 In some cases, you may use the same prefix for multiple paths.
92                 <classname>Zend_Loader_PluginLoader</classname> actually registers an
93                 array of paths for each given prefix; the last one registered
94                 will be the first one checked. This is particularly useful if
95                 you are utilizing incubator components.
96             </para>
97         </note>
99         <note>
100             <title>Paths may be defined at instantiation</title>
102             <para>
103                 You may optionally provide an array of prefix / path pairs (or
104                 prefix / paths -- plural paths are allowed) as a parameter to
105                 the constructor:
106             </para>
108             <programlisting language="php"><![CDATA[
109 $loader = new Zend_Loader_PluginLoader(array(
110     'Zend_View_Helper' => 'Zend/View/Helper/',
111     'Foo_View_Helper'  => 'application/modules/foo/views/helpers',
112     'Bar_View_Helper'  => 'application/modules/bar/views/helpers'
114 ]]></programlisting>
115         </note>
117         <para>
118             <classname>Zend_Loader_PluginLoader</classname> also optionally allows you to
119             share plugins across plugin-aware objects, without needing to
120             utilize a singleton instance. It does so via a static registry.
121             Indicate the registry name at instantiation as the second parameter
122             to the constructor:
123         </para>
125         <programlisting language="php"><![CDATA[
126 // Store plugins in static registry 'foobar':
127 $loader = new Zend_Loader_PluginLoader(array(), 'foobar');
128 ]]></programlisting>
130         <para>
131             Other components that instantiate the <code>PluginLoader</code>
132             using the same registry name will then have access to already loaded
133             paths and plugins.
134         </para>
135     </sect2>
137     <sect2 id="zend.loader.pluginloader.paths">
138         <title>Manipulating Plugin Paths</title>
140         <para>
141             The example in the previous section shows how to add paths to a
142             plugin loader. What if you want to determine the paths already
143             loaded, or remove one or more?
144         </para>
146         <itemizedlist>
147             <listitem>
148                 <para>
149                     <methodname>getPaths($prefix = null)</methodname> returns all paths as
150                     prefix / path pairs if no <varname>$prefix</varname> is provided,
151                     or just the paths registered for a given prefix if a
152                     <varname>$prefix</varname> is present.
153                 </para>
154             </listitem>
156             <listitem>
157                 <para>
158                     <methodname>clearPaths($prefix = null)</methodname> will clear all
159                     registered paths by default, or only those associated with a
160                     given prefix, if the <varname>$prefix</varname> is provided and
161                     present in the stack.
162                 </para>
163             </listitem>
165             <listitem>
166                 <para>
167                     <methodname>removePrefixPath($prefix, $path = null)</methodname> allows
168                     you to selectively remove a specific path associated with a
169                     given prefix. If no <varname>$path</varname> is provided, all
170                     paths for that prefix are removed. If a <varname>$path</varname>
171                     is provided and exists for that prefix, only that path will
172                     be removed.
173                 </para>
174             </listitem>
175         </itemizedlist>
176     </sect2>
178     <sect2 id="zend.loader.pluginloader.checks">
179         <title>Testing for Plugins and Retrieving Class Names</title>
181         <para>
182             Sometimes you simply want to determine if a plugin class has been
183             loaded before you perform an action. <methodname>isLoaded()</methodname> takes a
184             plugin name, and returns the status.
185         </para>
187         <para>
188             Another common use case for the <code>PluginLoader</code> is to
189             determine fully qualified plugin class names of loaded classes;
190             <methodname>getClassName()</methodname> provides this functionality. Typically,
191             this would be used in conjunction with <methodname>isLoaded()</methodname>:
192         </para>
194         <programlisting language="php"><![CDATA[
195 if ($loader->isLoaded('Adapter')) {
196     $class   = $loader->getClassName('Adapter');
197     $adapter = call_user_func(array($class, 'getInstance'));
199 ]]></programlisting>
200     </sect2>
202     <sect2 id="zend.loader.pluginloader.performance">
203         <title>Getting Better Performance for Plugins</title>
205         <para>
206             Plugin loading can be an expensive operation. At its heart, it needs
207             to loop through each prefix, then each path on the prefix, until it
208             finds a file that matches -- and which defines the class expected.
209             In cases where the file exists but does not define the class, an
210             error will be added to the <acronym>PHP</acronym> error stack, which is also an
211             expensive operation. The question then turns to: how can you keep
212             the flexibility of plugins and also address performance?
213         </para>
215         <para>
216             <classname>Zend_Loader_PluginLoader</classname> offers an opt-in feature for
217             just this situation, a class file include cache. When enabled, it
218             will create a file that contains all successful includes which you
219             can then call from your bootstrap. Using this strategy, you can
220             greatly improve the performance of your production servers.
221         </para>
223         <example id="zend.loader.pluginloader.performance.example">
224             <title>Using the PluginLoader class file include cache</title>
226             <para>
227                 To use the class file include cache, simply drop the
228                 following code into your bootstrap:
229             </para>
231             <programlisting language="php"><![CDATA[
232 $classFileIncCache = APPLICATION_PATH . '/../data/pluginLoaderCache.php';
233 if (file_exists($classFileIncCache)) {
234     include_once $classFileIncCache;
236 Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);
237 ]]></programlisting>
239             <para>
240                 Obviously, the path and filename will vary based on your needs.
241                 This code should come as early as possible, to ensure that
242                 plugin-based components can make use of it.
243             </para>
245             <para>
246                 During development, you may wish to disable the cache. One
247                 method for doing so is to use a configuration key for
248                 determining whether or not the plugin loader should cache.
249             </para>
251             <programlisting language="php"><![CDATA[
252 $classFileIncCache = APPLICATION_PATH . '/../data/pluginLoaderCache.php';
253 if (file_exists($classFileIncCache)) {
254     include_once $classFileIncCache;
256 if ($config->enablePluginLoaderCache) {
257     Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);
259 ]]></programlisting>
261             <para>
262                 This technique allows you to keep your modifications to your
263                 configuration file rather than code.
264             </para>
265         </example>
266     </sect2>
267 </sect1>
268 <!--
269 vim:se ts=4 sw=4 et: