Cloader——仿Zend_Autoloader,自动加载类

posted by admin on 2010-04-14 | Comments (0) | Last updated on 2011-03-26
最近在用CI写点东东,发现自带的类加载方式超级不好用(以前用惯了zend的),于是参考qee动手修改下,做了个Cloader,代码如下:

<?php
/**
* DIRECTORY_SEPARATOR 的简写
*/
define('DS', DIRECTORY_SEPARATOR);
class Cloader
{
/**
* 类搜索路径
*
* @var array
*/
private static $_class_path = array();
/**
* 类搜索路径的选项
*
* @var array
*/
private static $_class_path_options = array();
/**
* 载入指定类的定义文件,如果载入失败抛出异常
*
* @code php
* Q::loadClass('Table_Posts');
* @endcode
*
* $dirs 参数可以是一个以 PATH_SEPARATOR 常量分隔的字符串,
* 也可以是一个包含多个目录名的数组。
*
* @code php
* Q::loadClass('Table_Posts', array('/www/mysite/app', '/www/mysite/lib'));
* @endcode
*
* @param string $class_name 要载入的类
* @param string|array $dirs 指定载入类的搜索路径
*
* @return string|boolean 成功返回类名,失败返回 false
*/
static function loadClass($class_name, $dirs = null, $throw = true)
{
if (class_exists($class_name, false) || interface_exists($class_name, false))
{
return $class_name;
}
$filename = str_replace('_', DS, $class_name);
if ($filename != $class_name)
{
$dirname = dirname($filename);
if (!empty($dirs))
{
if (!is_array($dirs))
{
$dirs = explode(PATH_SEPARATOR, $dirs);
}
}
else
{
$dirs = self::$_class_path;
}
$filename = basename($filename) . '.php';
return self::loadClassFile($filename, $dirs, $class_name, $dirname, $throw);
}
else
{
return self::loadClassFile("{$filename}.php", self::$_class_path, $class_name, '', $throw);
}
}
/**
* 添加一个类搜索路径
*
* 如果要使用 Core::loadClass() 载入非 系统 的类,需要通过 Core::import() 添加类类搜索路径。
*
* 要注意,Core::import() 添加的路径和类名称有关系。
*
* 例如类的名称为 Vendor_Smarty_Adapter,那么该类的定义文件存储结构就是 vendor/smarty/adapter.php。
* 因此在用 Q::import() 添加 Vendor_Smarty_Adapter 类的搜索路径时,
* 只能添加 vendor/smarty/adapter.php 的父目录。
*
* @code php
* Core::import('/www/app');
* Core::loadClass('Vendor_Smarty_Adapter');
* // 实际载入的文件是 /www/app/vendor/smarty/adapter.php
* @endcode
*
* 由于规范是文件名全小写,因此要载入文件名存在大小写区分的第三方库时,
* 应该指定 import() 方法的第二个参数。
*
* @code php
* Q::import('/www/app/vendor');
* Q::loadClass('Zend_Mail');
* // 实际载入的文件是 /www/app/vendor/Zend/Mail.php
* @endcode
*
* @param string $dir 要添加的搜索路径
* @param boolean $case_sensitive 在该路径中查找类文件时是否区分文件名大小写
*/
static function import($dir, $case_sensitive = false)
{
$real_dir = realpath($dir);
if ($real_dir)
{
$dir = rtrim($real_dir, '/\\');
if (!isset(self::$_class_path[$dir]))
{
self::$_class_path[$dir] = $dir;
self::$_class_path_options[$dir] = $case_sensitive;
}
}
}
/**
* 载入特定文件,并检查是否包含指定类的定义
*
* 该方法从 $dirs 参数提供的目录中查找并载入 $filename 参数指定的文件。
* 然后检查该文件是否定义了 $class_name 参数指定的类。
*
* 如果没有找到指定类,则抛出异常。
*
* @code php
* Core::loadClassFile('Smarty.class.php', $dirs, 'Smarty');
* @endcode
*
* @param string $filename 要载入文件的文件名(含扩展名)
* @param string|array $dirs 文件的搜索路径
* @param string $class_name 要检查的类
* @param string $dirname 是否在查找文件时添加目录前缀
* @param string $throw 是否在找不到类时抛出异常
*/
static function loadClassFile($filename, $dirs, $class_name, $dirname = '', $throw = true)
{
if (!is_array($dirs))
{
$dirs = explode(PATH_SEPARATOR, $dirs);
}
if ($dirname)
{
$filename = rtrim($dirname, '/\\') . DS . $filename;
}
$filename_l = strtolower($filename);
foreach ($dirs as $dir)
{
if (isset(self::$_class_path[$dir]))
{
$path = $dir . DS . (self::$_class_path_options[$dir] ? $filename : $filename_l);
}
else
{
$path = rtrim($dir, '/\\') . DS . $filename;
}
//echo $path.'<br>';
if (is_file($path))
{
require $path;
break;
}
}
// 载入文件后判断指定的类或接口是否已经定义
if (!class_exists($class_name, false) && ! interface_exists($class_name, false))
{
if ($throw)
{
throw new Exception("$path $filename does not exist in this PHP installation");;
}
return false;
}
return $class_name;
}
/**
* 载入指定的文件
*
* 该方法从 $dirs 参数提供的目录中查找并载入 $filename 参数指定的文件。
* 如果文件不存在,则根据 $throw 参数决定是否抛出异常。
*
* 与 PHP 内置的 require 和 include 相比,Q::loadFile() 会多处下列特征:
*
* <ul>
* <li>检查文件名是否包含不安全字符;</li>
* <li>检查文件是否可读;</li>
* <li>文件无法读取时将抛出异常。</li>
* </ul>
*
* @code php
* Q::loadFile('my_file.php', $dirs);
* @endcode
*
* @param string $filename 要载入文件的文件名(含扩展名)
* @param array $dirs 文件的搜索路径
* @param boolean $throw 在找不到文件时是否抛出异常
*
* @return mixed
*/
static function loadFile($filename, $dirs = null, $throw = true)
{
if (preg_match('/[^a-z0-9\-_.]/i', $filename))
{
throw new Exception("$filename does not exist in this PHP installation");
}
if (is_null($dirs))
{
$dirs = array();
}
elseif (is_string($dirs))
{
$dirs = explode(PATH_SEPARATOR, $dirs);
}
foreach ($dirs as $dir)
{
$path = rtrim($dir, '\\/') . DS . $filename;
if (is_file($path)) return include $path;
}
if ($throw) throw new Exception("$filename does not exist in this PHP installation");
return false;
}
/**
* 用于类自动载入,不需要由开发者调用
*
* @param string $class_name
*/
static function autoload($class_name)
{
self::loadClass($class_name, null, false);
}
/**
* 注册或取消注册一个自动类载入方法
*
* 该方法参考 Zend Framework。
*
* @param string $class 提供自动载入服务的类
* @param boolean $enabled 启用或禁用该服务
*/
static function registerAutoload($class = __CLASS__, $enabled = true)
{
if (!function_exists('spl_autoload_register'))
{
throw new Exception('spl_autoload does not exist in this PHP installation');
}

if(empty(self::$_class_path))
{
self::$_class_path = explode(PATH_SEPARATOR,get_include_path());
}
if ($enabled === true)
{
spl_autoload_register(array($class, 'autoload'));
}
else
{
spl_autoload_unregister(array($class, 'autoload'));
}
}
}
/**
* 设置对象的自动载入
*/
Cloader::registerAutoload();
文章评分

发表评论

您的IP: 38.107.179.237 美国 局域网/未知

0个评论

    莫非?这就是传说中的沙发...有木有!