本文實例分析了Zend Framework中Loader以及PluginLoader用法。分享給大家供大家參考,具體如下:
Zend Framework提供了Zend_Loader,用來動態加載文件。
以下是具體用法,以及具體實現:
1.加載文件
使用方法:
Zend_Loader::loadFile($filename, $dirs=null, $once=false);
具體實現:
/**
* Loads a PHP file. This is a wrapper for PHP's include() function.
*
* $filename must be the complete filename, including any
* extension such as ".php". Note that a security check is performed that
* does not permit extended characters in the filename. This method is
* intended for loading Zend Framework files.
*
* If $dirs is a string or an array, it will search the directories
* in the order supplied, and attempt to load the first matching file.
*
* If the file was not found in the $dirs, or if no $dirs were specified,
* it will attempt to load it from PHP's include_path.
*
* If $once is TRUE, it will use include_once() instead of include().
*
* @param string $filename
* @param string|array $dirs - OPTIONAL either a path or array of paths
* to search.
* @param boolean $once
* @return boolean
* @throws Zend_Exception
*/
public static function loadFile($filename, $dirs = null, $once = false)
{
self::_securityCheck($filename);
/**
* Search in provided directories, as well as include_path
*/
$incPath = false;
if (!empty($dirs) && (is_array($dirs) || is_string($dirs))) {
if (is_array($dirs)) {
$dirs = implode(PATH_SEPARATOR, $dirs);
}
$incPath = get_include_path();
set_include_path($dirs . PATH_SEPARATOR . $incPath);
}
/**
* Try finding for the plain filename in the include_path.
*/
if ($once) {
include_once $filename;
} else {
include $filename;
}
/**
* If searching in directories, reset include_path
*/
if ($incPath) {
set_include_path($incPath);
}
return true;
}
參數規則:
正如實現方法,有如下參數
$filename參數指定需要加載的文件,注意$filename不需要指定任何路徑,只需要文件名即可。ZF會對文件作安全性檢查。$filename 只能由字母,數字,連接符-,下劃線_及英文句號.組成(半角)。$dirs參數則不限,可以使用中文等。
$dirs 參數用來指定文件所在目錄,可以是一個字符串或者數組。如果為 NULL,則程序將會到系統的 include_path 下尋找文件是否存在(include_path可在php.ini中設置--Haohappy注),如果是字符串或數組,則會到指定的目錄下去找,然後才是 include_path。
$once 參數為布爾類型,如果為 TRUE,Zend_Loader::loadFile() 使用 PHP 函數 » include_once() 加載文件,否則就是 PHP 函數 » include()。(本參數只能是true或false,兩者區別就和include()和include_once()的區別一樣。)
2.加載類
具體使用:
Zend_Loader::loadClass('Container_Tree',
array(
'/home/production/mylib',
'/home/production/myapp'
)
);
具體實現:
/**
* Loads a class from a PHP file. The filename must be formatted
* as "$class.php".
*
* If $dirs is a string or an array, it will search the directories
* in the order supplied, and attempt to load the first matching file.
*
* If $dirs is null, it will split the class name at underscores to
* generate a path hierarchy (e.g., "Zend_Example_Class" will map
* to "Zend/Example/Class.php").
*
* If the file was not found in the $dirs, or if no $dirs were specified,
* it will attempt to load it from PHP's include_path.
*
* @param string $class - The full class name of a Zend component.
* @param string|array $dirs - OPTIONAL Either a path or an array of paths
* to search.
* @return void
* @throws Zend_Exception
*/
public static function loadClass($class, $dirs = null)
{
if (class_exists($class, false) || interface_exists($class, false)) {
return;
}
if ((null !== $dirs) && !is_string($dirs) && !is_array($dirs)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('Directory argument must be a string or an array');
}
// Autodiscover the path from the class name
// Implementation is PHP namespace-aware, and based on
// Framework Interop Group reference implementation:
// http://groups.google.com/group/php-standards/web/psr-0-final-proposal
$className = ltrim($class, '\\');
$file = '';
$namespace = '';
if ($lastNsPos = strripos($className, '\\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$file = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$file .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
if (!empty($dirs)) {
// use the autodiscovered path
$dirPath = dirname($file);
if (is_string($dirs)) {
$dirs = explode(PATH_SEPARATOR, $dirs);
}
foreach ($dirs as $key => $dir) {
if ($dir == '.') {
$dirs[$key] = $dirPath;
} else {
$dir = rtrim($dir, '\\/');
$dirs[$key] = $dir . DIRECTORY_SEPARATOR . $dirPath;
}
}
$file = basename($file);
self::loadFile($file, $dirs, true);
} else {
self::loadFile($file, null, true);
}
if (!class_exists($class, false) && !interface_exists($class, false)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("File \"$file\" does not exist or class \"$class\" was not found in the file");
}
}
$class 類名將會根據下劃線(作為目錄分隔線)對應到相應目錄下的PHP文件,並加上'.php',比如Container_Tree會指向Container\\Tree.php。
$dir 可以是數組或者字符串。目錄是除去類名包含的目錄的路徑。
3.判斷某個文件是否可讀
具體使用:
if (Zend_Loader::isReadable($filename)) {
// do something with $filename
}
具體實現:
/**
* Returns TRUE if the $filename is readable, or FALSE otherwise.
* This function uses the PHP include_path, where PHP's is_readable()
* does not.
*
* Note from ZF-2900:
* If you use custom error handler, please check whether return value
* from error_reporting() is zero or not.
* At mark of fopen() can not suppress warning if the handler is used.
*
* @param string $filename
* @return boolean
*/
public static function isReadable($filename)
{
if (is_readable($filename)) {
// Return early if the filename is readable without needing the
// include_path
return true;
}
if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'
&& preg_match('/^[a-z]:/i', $filename)
) {
// If on windows, and path provided is clearly an absolute path,
// return false immediately
return false;
}
foreach (self::explodeIncludePath() as $path) {
if ($path == '.') {
if (is_readable($filename)) {
return true;
}
continue;
}
$file = $path . '/' . $filename;
if (is_readable($file)) {
return true;
}
}
return false;
}
具體參數:
$filename參數指定了要檢查的文件名,包括路徑信息。這個方法是將 PHP 函數» is_readable()封裝而成的,is_readable() 不會自動查找 include_path 下的文件,而 Zend::isReadable() 可以。
4.Autoloader
這個類的Autoloader功能已經不推薦使用了,所以不再講述。還有其他的Autoloader,以後具體說明。
5.插件加載器
幫助文章給出的具體實例如下,可參考使用:
很多 Zend Framework 組件支持插件,允許通過指定類的前綴和到類的文件(不需要在 include_path或不需要遵循傳統命名約定的文件)的路徑動態加載函數。Zend_Loader_PluginLoader 提供了普通的函數來完成這個工作。
PluginLoader 的基本用法遵循 Zend Framework 的命名約定(一個文件一個類),解析路徑時,使用下劃線作為路徑分隔符。當決定是否加載特別的插件類,允許傳遞可選的類前綴來預處理。另外,路徑按 LIFO 順序來搜索。由於 LIFO 搜索和類的前綴,允許命名空間給插件,這樣可以從早期注冊的路徑來覆蓋插件。
基本用例
首先,假定下面的目錄結構和類文件,並且根(toplevel)目錄和庫目錄在 include_path 中:
application/
modules/
foo/
views/
helpers/
FormLabel.php
FormSubmit.php
bar/
views/
helpers/
FormSubmit.php
library/
Zend/
View/
Helper/
FormLabel.php
FormSubmit.php
FormText.php
現在,創建一個插件加載器來使各種各樣的視圖助手倉庫可用:
<?php
$loader = new Zend_Loader_PluginLoader();
$loader->addPrefixPath('Zend_View_Helper', 'Zend/View/Helper/')
->addPrefixPath('Foo_View_Helper', 'application/modules/foo/views/helpers')
->addPrefixPath('Bar_View_Helper', 'application/modules/bar/views/helpers');
?>
接著用類名中添加路徑時定義的前綴後面的部分來加載一個給定的視圖助手:
<?php
// load 'FormText' helper:
$formTextClass = $loader->load('FormText'); // 'Zend_View_Helper_FormText';
// load 'FormLabel' helper:
$formLabelClass = $loader->load('FormLabel'); // 'Foo_View_Helper_FormLabel'
// load 'FormSubmit' helper:
$formSubmitClass = $loader->load('FormSubmit'); // 'Bar_View_Helper_FormSubmit'
?>
類加載後,就可以實例化了。
Note: 為一個前綴注冊多個路徑
有時候,多個路徑使用相同的前綴,Zend_Loader_PluginLoader 實際上為每個給定的前綴注冊一個路徑數組;最後注冊的被首先檢查,當你使用孵化器裡的組件時,這相當有用。
Note: 實例化時定義路徑
你可以提供給構造器一個可選的“前綴/路徑”對(或“前綴/多個路徑”)數組參數:
<?php $loader = new Zend_Loader_PluginLoader(array( 'Zend_View_Helper' => 'Zend/View/Helper/', 'Foo_View_Helper' => 'application/modules/foo/views/helpers', 'Bar_View_Helper' => 'application/modules/bar/views/helpers' )); ?>
Zend_Loader_PluginLoader 在不需要使用單態實例的情況下,也可選地允許共享插件,這是通過靜態注冊表來完成的,在實例化時需要注冊表名作為構造器的第二個參數:
<?php // Store plugins in static registry 'foobar': $loader = new Zend_Loader_PluginLoader(array(), 'foobar'); ?>
其它使用同名注冊表來實例化 PluginLoader 的組件將可以訪問已經加載的路徑和插件。
處理插件路徑
上節的例子示例如何給插件加載器添加路徑,那麼如何確定已經加載的路徑或刪除他們呢?
如果沒有提供 $prefix,getPaths($prefix = null) 以“前綴/路徑”對返回所有的路徑;或者如果提供了 $prefix,getPaths($prefix = null) 返回為給定的前綴注冊的路徑。
clearPaths($prefix = null) 將缺省地清除所有的已注冊路徑,或者如果提供了 $prefix 並放在堆棧裡,只清除和那些和給定前綴關聯的路徑。
removePrefixPath($prefix, $path = null) 允許有選擇地清除和給定前綴相關的特定的路徑。如果沒有提供 $path ,所有的和前綴相關的路徑被清除,如果提供了 $path 並且相應的前綴存在,只有這個相關的路徑被清除。
測試插件和獲取類的名字
有時候你想確定在執行一個動作之前是否插件類已經加載,isLoaded() 返回插件名的狀態。
PluginLoader 的另一個普通用例是確定已加載類的完全合格的插件類名,getClassName() 提供該功能。一般地,這個和 isLoaded() 聯合使用:
<?php
if ($loader->isLoaded('Adapter')) {
$class = $loader->getClassName('Adapter');
$adapter = call_user_func(array($class, 'getInstance'));
}
?>
具體插件加載器的實現可以參考Zend_Loader_PluginLoader和Zend_Loader。這裡不在累述。
更多關於zend相關內容感興趣的讀者可查看本站專題:《Zend FrameWork框架入門教程》、《php優秀開發框架總結》、《Yii框架入門及常用技巧總結》、《ThinkPHP入門教程》、《php面向對象程序設計入門教程》、《php+mysql數據庫操作入門教程》及《php常見數據庫操作技巧匯總》
希望本文所述對大家PHP程序設計有所幫助。