本篇文章主要是在分析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