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()方法,獲取前端控制器,然後前端控制器執行對請求的應答過程。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章