ZendFramework资源加载过程分析

来源:互联网 发布:公司申请软件专利 编辑:程序博客网 时间:2024/06/06 09:40

本篇文章主要是在分析ZendFramework1.11版对自定义的Resource的加载过程,也是个人在分析过程中遇到问题的整理
1、为了了解这个过程我们先从网上已有的Resource的开发实例(正确的示例)配置产品
在library目录下添加resource目录作为个人开发resource插件的路径;
增加一个View插件,替换掉现有的bootstrap.php下面的initView方法
<?php
class Resource_View extends Zend_Application_Resource_ResourceAbstract
{
    protected $_view;
 
    public function init()
    {
        // Return view so bootstrap will store it in the registry
        return $this->getView();
    }
 
    public function getView()
    {
        if (null === $this->_view) {
            $options = $this->getOptions();
            $title   = '';
            if (array_key_exists('title', $options)) {
                $title = $options['title'];
                unset($options['title']);
            }
 
            $view = new Zend_View($options);
            $view->doctype('XHTML1_STRICT');
            $view->headTitle($title);
            $view->headLink()->appendStylesheet('/css/site.css');
            $view->headScript()->appendfile('/js/analytics.js');
 
            $viewRenderer =
                Zend_Controller_Action_HelperBroker::getStaticHelper(
                    'ViewRenderer'
                );
            $viewRenderer->setView($view);
 
            $this->_view = $view;
          }
          return $this->_view; }
}
这样我们就有了一个resource了,下一步需要配置Zend使其加载
个人喜欢使用php数组来配置Zend(ZF2.0也使用了数组 : ) )
<?php
//product
$phpSettings['display_startup_errors'] = 0;
$phpSettings['display_errors'] = 0;
$bootstrap['path'] = APPLICATION_PATH . "/Bootstrap.php";
$bootstrap['class'] = "Bootstrap";
$resources['frontController']['controllerDirectory'] = APPLICATION_PATH . "/controllers";
$resources['frontController']['params']['displayExceptions'] = 0;
$resources['view'] = true;
$autoloaderNamespaces = "Resource_";
$pluginpaths['Resource'] = "resource";

$configs['autoloaderNamespaces'][] = $autoloaderNamespaces;
$configs['pluginpaths'] = $pluginpaths;
$configs['phpSettings'] = $phpSettings;
$configs['includePaths'] = $includePaths;
$configs['bootstrap'] = $bootstrap;
$configs['appnamespace'] = "Application";
$configs['resources'] = $resources;
$configs['path'] = APPLICATION_PATH . "/views/scripts";
这个里面增加的有resource数组中的View,表示增加我们的自定义的View资源;
autoloaderNamespaces增加资源的命名空间,涉及到ZF1的文件自动加载问题;
pluginpaths增加自定义资源的插件路径,也就是在include_path下面的路径(个人感觉有些多余)

2、ZF1初始化和资源加载
主要在index.php入口文件中的application的加载过程实现这个部分,我们来看看这个过程
$application = new Zend_Application(
APPLICATION_ENV,
$configs);
$application->bootstrap()
            ->run();
Zend_Application实例化包含类加载器的实例化,设置配置参数。
require_once 'Zend/Loader/Autoloader.php';
$this->_autoloader = Zend_Loader_Autoloader::getInstance();
设置参数实际上就是帮助开发者自动设置phpsetting,includepath,自动加载命名空间(autoloadernamespaces),实例化bootstrap类(这个实例化过程加载了Frontcontroller资源,加载在Zend_Application_Bootstrap_Bootstrap的类构造方法中),具体看setOptions方法。
补充:pluginpaths这个参数会在Zend_Application_Bootstrap_BootstrapAbstract的setOptions这个方法中被添加为插件加载器的路径参数
自动加载命名空间(autoloadernamespaces):设置了自动加载器可以加载的类前缀部分,如果不设置自定义的类命名空间,就会无法加载相应类,这个设置可以在配置文件中做(application.php|application.ini),也可以手动设置通过$loader->registerNamespace($namespace)来实现,具体可以看Zend_Loader_Autoloader.php文件。
$application的bootstrap()方法主要加载Resource,包括框架必须的Resource和自定义的,加载的过程在Zend_Application_Bootstrap_BootstrapAbstract类的_bootstrap方法中实现
protected function _bootstrap($resource = null)
    {
        if (null === $resource) {
            foreach ($this->getClassResourceNames() as $resource) {
                $this->_executeResource($resource);
            }

            foreach ($this->getPluginResourceNames() as $resource) {
                $this->_executeResource($resource);
            }
        } elseif (is_string($resource)) {
            $this->_executeResource($resource);
        } elseif (is_array($resource)) {
            foreach ($resource as $r) {
                $this->_executeResource($r);
            }
        } else {
            throw new Zend_Application_Bootstrap_Exception('Invalid argument passed to ' . __METHOD__);
        }
    }
主要有两个部分的处理
1、加载类定义的资源,基本都是个人在开发中通过_init方法定义的资源初始化行为,这个过程通过getClassResourceNames方法获取类资源,通过ReflectionObject或get_class_methods方法实现类方法名的获取
例如:在Bootstrap.php中定义一个如下方法,就可以自动被执行并初始化Request资源
protected function _initRequest()
{
    // Ensure front controller instance is present, and fetch it
    $this->bootstrap('FrontController');
    $front = $this->getResource('FrontController');
 
    // Initialize the request object
    $request = new Zend_Controller_Request_Http();
    $request->setBaseUrl('/foo');
    // Add it to the front controller
    $front->setRequest($request);
 
    // Bootstrap will store this value in the 'request' key of its container
    return $request;
 }
2、加载自定义的类资源,加载配置中设置的资源,也可以加载bootstrap方法给的参数资源(由于资源存在多处设置加载的问题,_executeResource中增加了资源的是否加载的判断),由Zend_Application_Bootstrap_BootstrapAbstract的_bootstrap方法执行加载
protected function _bootstrap($resource = null)
    {
        if (null === $resource) {
            foreach ($this->getClassResourceNames() as $resource) {
                $this->_executeResource($resource);
            }

            foreach ($this->getPluginResourceNames() as $resource) {
                $this->_executeResource($resource);
            }
        } elseif (is_string($resource)) {
            $this->_executeResource($resource);
        } elseif (is_array($resource)) {
            foreach ($resource as $r) {
                $this->_executeResource($r);
            }
        } else {
            throw new Zend_Application_Bootstrap_Exception('Invalid argument passed to ' . __METHOD__);
        }
    }
加载的过程在_loadPluginResource中执行,Zend_Loader_PluginLoader的load会根据resource的名称验证并返回类名,在Zend_Application_Bootstrap_BootstrapAbstract的_loadPluginResource中实例化并注册资源插件
protected function _loadPluginResource($resource, $options)
    {
        $options   = (array) $options;
        $options['bootstrap'] = $this;
        $className = $this->getPluginLoader()->load(strtolower($resource), false);

        if (!$className) {
            return false;
        }

        $instance = new $className($options);

       unset($this->_pluginResources[$resource]);
        if (isset($instance->_explicitType)) {
            $resource = $instance->_explicitType;
        }
        $resource = strtolower($resource);
        $this->_pluginResources[$resource] = $instance;

        return $resource;
    }


接下来就是在_executeResource中执行资源的init方法,然后把init的返回结果保存在_container容器中(就是一个Zend_Registry实例),资源的加载和缓存也就OK了。

参考:

http://blog.madarco.net/327/how-to-make-your-own-zend-framework-resource-plugin/

http://framework.zend.com/manual/1.11/en/zend.application.html

原创粉丝点击