1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="zend.loader.pluginloader">
4 <title>Loading Plugins</title>
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
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.
25 <sect2 id="zend.loader.pluginloader.usage">
26 <title>Basic Use Case</title>
29 First, let's assume the following directory structure and class
30 files, and that the top level directory and library directory are on
34 <programlisting language="txt"><![CDATA[
56 Now, let's create a plugin loader to address the various view
57 helper repositories available:
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');
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:
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'
86 Once the class is loaded, we can now instantiate it.
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.
100 <title>Paths may be defined at instantiation</title>
103 You may optionally provide an array of prefix / path pairs (or
104 prefix / paths -- plural paths are allowed) as a parameter to
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'
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
125 <programlisting language="php"><![CDATA[
126 // Store plugins in static registry 'foobar':
127 $loader = new Zend_Loader_PluginLoader(array(), 'foobar');
131 Other components that instantiate the <code>PluginLoader</code>
132 using the same registry name will then have access to already loaded
137 <sect2 id="zend.loader.pluginloader.paths">
138 <title>Manipulating Plugin Paths</title>
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?
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.
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.
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
178 <sect2 id="zend.loader.pluginloader.checks">
179 <title>Testing for Plugins and Retrieving Class Names</title>
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.
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>:
194 <programlisting language="php"><![CDATA[
195 if ($loader->isLoaded('Adapter')) {
196 $class = $loader->getClassName('Adapter');
197 $adapter = call_user_func(array($class, 'getInstance'));
202 <sect2 id="zend.loader.pluginloader.performance">
203 <title>Getting Better Performance for Plugins</title>
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?
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.
223 <example id="zend.loader.pluginloader.performance.example">
224 <title>Using the PluginLoader class file include cache</title>
227 To use the class file include cache, simply drop the
228 following code into your bootstrap:
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);
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.
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.
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);
262 This technique allows you to keep your modifications to your
263 configuration file rather than code.