YLoader.class.php 6.39 KB
<?php/**
 * 加载类
 * 
 * @example
 * <pre>
 *   set_include_path(
 *   	'.' . PATH_SEPARATOR . get_include_path()
 *   );
 *   $prefixes = array(
 *   	'Framework_' => __DIR__ . '/util',
 *      ...
 *   );
 *   $loader = new YLoader();
 *   $loader->setSuffix('.class.php')
 *          ->setPrefixes($prefixes)
 *          ->setUseIncludePath(true)
 *          ->register();
 * </pre>
 * 
 * @name YLoader
 * @package Yoho.Util.Framework
 * @copyright yoho.inc
 * @version 1.1 (2012-06-28 14:25:20)
 * @author fei.hong <hf@yoho.cn>
 * @since 1.0
 */defined('DS') || define('DS', DIRECTORY_SEPARATOR);
class Framework_YLoader{
    /**
     * 后缀名
     * 
     * @var array
     * @since 1.1
     */
    private $suffix = '.class.php';
    
    /**
     * 前缀列表
     * 
     * @var array
     * @since 1.1
     */
    private $prefixes = array();
    
    /**
     * 使用可靠的文件目录
     * 
     * @var array
     */
    private $fallbackDirs = array();
    
    /**
     * 使用当前系统引入路径
     * 
     * @var boolean
     */
    private $useIncludePath = false;

    /**
     * 获取后缀名
     * 
     * @return string
     * @since 1.1
     */
    public function getSuffix()
    {
        return $this->suffix;
    }
    
    /**
     * 获取前缀列表
     *
     * @return array
     * @since 1.1
     */
    public function getPrefixes()
    {
        return $this->prefixes;
    }

    /**
     * 获取可靠的文件目录
     *
     * @return array
     */
    public function getFallbackDirs()
    {
        return $this->fallbackDirs;
    }
    
    /**
     * 用于加载时检查是否使用加载路径
     * 
     * @return boolean
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }
    
    /**
     * 设置后缀
     * 
     * @param string $suffix 后缀名
     * @return object
     * @since 1.1
     */
    public function setSuffix($suffix)
    {
        $this->suffix = $suffix;
        
        return $this;
    }
    
    /**
     * 设置前缀
     *
     * @param string $prefix 类文件前缀
     * @param mixed array | string $paths 目录
     * @return void
     * @since 1.1
     */
    public function setPrefix($prefix, $paths)
    {
        if (! $prefix) 
        {
            foreach ((array) $paths as $path) 
            {
                $this->fallbackDirs[] = $path;
            }

            return;
        }
        
        if (isset($this->prefixes[$prefix])) 
        {
            $this->prefixes[$prefix] = array_merge(
                $this->prefixes[$prefix],
                (array) $paths
            );
        } 
        else 
        {
            $this->prefixes[$prefix] = (array) $paths;
        }
    }

    /**
     * 设置前缀列表
     *
     * @param array $prefixes 前缀列表
     * @return object
     * @since 1.1
     */
    public function setPrefixes(array $prefixes)
    {
        foreach ($prefixes as $prefix => $path) 
        {
            $this->setPrefix($prefix, $path);
        }
        
        return $this;
    }

    /**
     * 设置使用加载路径
     *
     * @param boolean $useIncludePath 是否使用加载路径
     * @return object
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
        
        return $this;
    }

    /**
     * 注册
     *
     * @return void
     */
    public function register()
    {
        spl_autoload_register(array($this, 'loadClass'));
    }

    /**
     * 移除注册
     * 
     * @return void
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));
    }
    
    /**
     * 查找文件
     *
     * 规范化说明: 
     * 1. 统一目录小写 
     * 2. 统一类文件名首字母大写
     * 
     * @param string $class 文件名
     * @return string | false
     */
    public function findFile($class)
    {
    	$classPath = '';
    	$className = '';
    	
    	// 判断是否使用PHP5.3命名空间 格式: "\路径\路径\类文件名"
        if ('\\' == $class[0]) 
        {
            $class = substr($class, 1);
            if (false !== ($pos = strrpos($class, '\\')))
            {
            	$classPath = strtolower(str_replace('\\', DS, substr($class, 0, $pos + 1)));
            	$className = substr($class, $pos + 1);
            }
        }
        // 判断是否使用规范化格式: "路径_路径_类文件名"
        elseif (false !== ($pos = strrpos($class, '_')))
        {
        	$classPath = strtolower(str_replace('_', DS, substr($class, 0, $pos + 1)));
        	$className = substr($class, $pos + 1);
        }
        // 其它未定义格式的文件
        else
        {
        	$className = $class;
        }
        
        $classPath .= ucfirst($className) . $this->suffix;
        
        // 通过指定的前缀与目录映射关系查找文件
        foreach ($this->prefixes as $prefix => $dirs) 
        {
            if (0 === strpos($class, $prefix)) 
            {
                foreach ($dirs as $path) 
                {
                	$path .= DS . $classPath;
                    if (file_exists($path)) 
                    {
                        return $path;
                    }
                }
            }
        }

        // 通过指定的目录结构查找文件
        foreach ($this->fallbackDirs as $path) 
        {
        	$path .= DS . $classPath;
            if (file_exists($path)) 
            {
                return $path;
            }
        }
        
        // 使用当前系统加载的路径
        if ($this->useIncludePath) 
        {
            // PHP > 5.2 返回文件绝对路径
            if (function_exists('stream_resolve_include_path'))
            {
                return stream_resolve_include_path($classPath);
            }
            return $classPath;
        }
        
        return false;
    }

    /**
     * 加载类文件
     *
     * @param string $class 文件名
     * @return boolean (true:成功, false:失败)
     */
    public function loadClass($class)
    {
    	// 判断文件是否已经加载
    	if (class_exists($class, false)) 
    	{
    		return true;
    	}
    	
    	// 判断文件是否存在, 存在则加载文件
        if (false !== ($file = $this->findFile($class))) 
        {
            require $file;

            return true;
        }
        
        return false;
    }
}