Matthew Weier O'Phinney wrote:
We've already identified the HelperBroker as being in need of
refactoring to use Zend_Loader_PluginLoader. However, that class, too,
relies partially on the include_path when the paths provided are not
absolute paths. Have you had a chance to test any components that utilize
the plugin loader? These would include Zend_Form, Zend_View (in trunk
and the 1.6.0 release candidates), and Zend_Filter_Inflector. I'm
curious if the PluginLoader would need to be refactored.
I've only tested on 1.5.3 so far, with view helpers, controller action
helpers and controller plug-ins, however so long as all the paths ZF
adds by default are absolute, the decision of whether or not to use
absolute paths or include the library paths in include_path can be left
to the user. As the plugin loader has no addPrefix() method the problem
from the HelperBroker isn't an issue, but if there was a situation where
only the prefix was provided, then the refactoring would be as simple as
checking if there is a path, if there is then load as usual, if there
isn't then append the plugin name to the prefix and try to load that
class through the autoloader.
I'd love to see this flexibility. Perhaps you could help out with some
contributions? :)
I'd be happy to. Just let me know what needs doing.
Regarding my loader, the reason I decided to write my own was because as
my application grew and more modules were added, I was getting an ever
increasing number of paths in the include_path (as every module has a
models folder, and optionally a library folder with additional classes).
Having this many paths in the include_path seriously affects performance
(http://framework.zend.com/wiki/display/ZFDEV/Performance+-+Multiple+Include+Path+Order)
so I wanted to find a better solution.
What I've ended up with is a simple loader class that uses class
prefixes (in a similar but not identical way to the plugin loader) for
loading classes from multiple locations very efficiently. It uses a
regex to detect the relevant prefix for the current class and attempts
to include that file from each related path. It also uses the error
suppression method from the incubator Zend_Loader to suppress errors
when files are not found. This is more efficient than using is_readable
and allows other errors to appear unlike @include_once. I've attached a
simplified version of this if anyone wants to take a look/use it.
--
Jack
_paths[$prefix])) {
$this->_paths[$prefix] = array();
}
$this->_paths[$prefix][] = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$prefixes = array_map('preg_quote', array_keys($this->_paths), array_fill(0, count($this->_paths), '/'));
$this->_regex = '/^(' . implode('|', $prefixes) . ')[_$]/';
}
public function loadClass($class)
{
$this->_loadClass($class);
if (!class_exists($class , false)) {
throw new Exception("Class '{$class}' could not be loaded");
}
}
public function autoload($class)
{
$this->_loadClass($class);
}
protected function _loadClass($class)
{
$file = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
set_error_handler(array($this, 'errorHandler'));
if (isset($this->_regex ) && preg_match($this->_regex, $class, $match)) {
$paths = $this->_paths[$match[1]];
foreach ($paths as $path) {
include_once $path . $file;
if (class_exists($class , false)) {
break;
}
}
} else {
include_once $file;
}
restore_error_handler();
}
public function errorHandler($number, $message, $file, $line, array $context)
{
if (preg_match('/Failed (to open stream|opening .+ for inclusion)/i', $message)) {
return true;
}
return false;
}
}