zendFramework分析2:引导程序

zendFramework引导过程通过Application组件完成,由于是对老版本的兼容扩展,其实现起来感觉没有yii那样优雅,它把类库当做资源,而原来那些类库又没有统一的接口,因此又需要新写资源类来间接配置和获取相应的资源。


Zend_Application

zendFramework配置的加载通过入口文件实例Zend_Application来完成,构造方法通过初始化配置后,通过setOptions方法来加载应用的配置。在配置中主要有phpsettings、includepaths、autoloadernamespaces、autoloaderzfpath、bootstrap、appnamespace、resources等。

public function setOptions(array $options)
{
    if (!empty($options['config'])) {
        if (is_array($options['config'])) {
            $_options = array();
            foreach ($options['config'] as $tmp) {
                $_options = $this->mergeOptions($_options, $this->_loadConfig($tmp));
            }
            $options = $this->mergeOptions($_options, $options);
        } else {
            $options = $this->mergeOptions($this->_loadConfig($options['config']), $options);
        }
    }

    $this->_options = $options;

    $options = array_change_key_case($options, CASE_LOWER);
    $this->_optionKeys = array_keys($options);
    if (!empty($options['phpsettings'])) {
        $this->setPhpSettings($options['phpsettings']);
    }

    if (!empty($options['includepaths'])) {
        $this->setIncludePaths($options['includepaths']);
    }

    if (!empty($options['autoloadernamespaces'])) {
        $this->setAutoloaderNamespaces($options['autoloadernamespaces']);
    }

    if (!empty($options['autoloaderzfpath'])) {
        $autoloader = $this->getAutoloader();
        if (method_exists($autoloader, 'setZfPath')) {
            $zfPath    = $options['autoloaderzfpath'];
            $zfVersion = !empty($options['autoloaderzfversion'])
                        ? $options['autoloaderzfversion']
                        : 'latest';
            $autoloader->setZfPath($zfPath, $zfVersion);
        }
    }

    if (!empty($options['bootstrap'])) {
        $bootstrap = $options['bootstrap'];

        if (is_string($bootstrap)) {
            $this->setBootstrap($bootstrap);
        } elseif (is_array($bootstrap)) {
            if (empty($bootstrap['path'])) {
                throw new Zend_Application_Exception('No bootstrap path provided');
            }

            $path  = $bootstrap['path'];
            $class = null;

            if (!empty($bootstrap['class'])) {
                $class = $bootstrap['class'];
            }
            $this->setBootstrap($path, $class);
        } else {
            throw new Zend_Application_Exception('Invalid bootstrap information provided');
        }
    }

    return $this;
}
Bootstrap

在zf应用中,把框架中类库的看做资源,配置中以resources开头的都是资源相关配置,如resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"配置控制器所在的目录。Zend_Application通过配置实例化Bootstrap来配置资源。

public function setOptions(array $options)
{
    $this->_options = $this->mergeOptions($this->_options, $options);

    $options = array_change_key_case($options, CASE_LOWER);
    $this->_optionKeys = array_merge($this->_optionKeys, array_keys($options));

    $methods = get_class_methods($this);

    foreach ($methods as $key => $method) {
        $methods[$key] = strtolower($method);
    }

    if (array_key_exists('pluginpaths', $options)) {
        $pluginLoader = $this->getPluginLoader();

        foreach ($options['pluginpaths'] as $prefix => $path) {
            $pluginLoader->addPrefixPath($prefix, $path);
        }
        unset($options['pluginpaths']);
    }

    foreach ($options as $key => $value) {

        $method = 'set' . strtolower($key);

        if (in_array($method, $methods)) {
            $this->$method($value);
        } elseif ('resources' == $key) {
            foreach ($value as $resource => $resourceOptions) {
                $this->registerPluginResource($resource, $resourceOptions);
            }
        }
    }
    return $this;
}
配置加载好后,需要启动支持程序运行的,在_bootstrap()首先通过中getClassResourceNames()将获捕获导类中以_init开头的方法,这些方法是通过在引导类内部配置相关资源,然后获取配置中的资源并执行引导,在执行引导的时候会把资源注册在一个全局容器中,通过getResource($resource)方法可以获取容器中的资源。
/**
  * 获取内部和外部配置资源并执行
  */
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__);
    }
}
/**
  * Execute a resource 执行资源并注册全局资源实例
  */
protected function _executeResource($resource)
{
    $resourceName = strtolower($resource);
    if (in_array($resourceName, $this->_run)) {
        return;
    }

    if (isset($this->_started[$resourceName]) && $this->_started[$resourceName]) {
        throw new Zend_Application_Bootstrap_Exception('Circular resource dependency detected');
    }

    $classResources = $this->getClassResources();

    if (array_key_exists($resourceName, $classResources)) {
        $this->_started[$resourceName] = true;
        $method = $classResources[$resourceName];
        $return = $this->$method();
        unset($this->_started[$resourceName]);
        $this->_markRun($resourceName);

        if (null !== $return) {
            $this->getContainer()->{$resourceName} = $return;
        }

        return;
    }

    if ($this->hasPluginResource($resource)) {
        $this->_started[$resourceName] = true;
        $plugin = $this->getPluginResource($resource); 

        $return = $plugin->init();
        unset($this->_started[$resourceName]);
        $this->_markRun($resourceName);

        if (null !== $return) {
            $this->getContainer()->{$resourceName} = $return;
        }

        return;
    }

    throw new Zend_Application_Bootstrap_Exception('Resource matching "' . $resource . '" not found');
}

引导程序加载完成后,通过run()方法,获取前端控制器,然后前端控制器执行对请求的应答过程。


你可能感兴趣的:(exception,application,Path,Zend,resources,methods)