thinkphp3.2源码 ----- 自动加载

  • 知识预备

  • 写在前面
    tp3.2实现的自动加载可以通过命名空间自动定位到类文件,实现这样的效果除了合理的处理手段外,比较有规律的项目结构也是必不可少的。

    • 源码(ThinkPHP/Library/Think/Think.class.php):
      • 注册自动加载函数
public static function start()
    {
        // 注册AUTOLOAD方法
        spl_autoload_register('Think\Think::autoload');
.............................
  • autoload方法:
public static function autoload($class)
    {
        // 检查是否存在映射
        if (isset(self::$_map[$class])) {
            include self::$_map[$class];
        } elseif (false !== strpos($class, '\\')) {
            $name = strstr($class, '\\', true);
            if (in_array($name, array('Think', 'Org', 'Behavior', 'Com', 'Vendor')) || is_dir(LIB_PATH . $name)) {
                // Library目录下面的命名空间自动定位
                $path = LIB_PATH;
            } else {
                // 检测自定义命名空间 否则就以模块为命名空间
                $namespace = C('AUTOLOAD_NAMESPACE');
                $path      = isset($namespace[$name]) ? dirname($namespace[$name]) . '/' : APP_PATH;
            }
            $filename = $path . str_replace('\\', '/', $class) . EXT;
            if (is_file($filename)) {
                // Win环境下面严格区分大小写
                if (IS_WIN && false === strpos(str_replace('/', '\\', realpath($filename)), $class . EXT)) {
                    return;
                }
                include $filename;
            }
        } elseif (!C('APP_USE_NAMESPACE')) {
            // 自动加载的类库层
            foreach (explode(',', C('APP_AUTOLOAD_LAYER')) as $layer) {
                if (substr($class, -strlen($layer)) == $layer) {
                    if (require_cache(MODULE_PATH . $layer . '/' . $class . EXT)) {
                        return;
                    }
                }
            }
            // 根据自动加载路径设置进行尝试搜索
            foreach (explode(',', C('APP_AUTOLOAD_PATH')) as $path) {
                if (import($path . '.' . $class))
                // 如果加载类成功则返回
                {
                    return;
                }

            }
        }
    }
  • 自动加载:
    tp通过spl_aotuload_register()注册atuoload()方法,并且将当前引用类的类名传入:
    • 类库映射:
      tp支持给类文件别名,实现通过这个别名去映射这个类文件的路径,例如:
      Think\Think::addMap('Think\Log',THINK_PATH.'Think\Log.php');
     Think\Think::addMap('Org\Util\Array',THINK_PATH.'Org\Util\Array.php');

addMap():

 // 注册classmap
    public static function addMap($class, $map = '')
    {
        if (is_array($class)) {
            self::$_map = array_merge(self::$_map, $class);
        } else {
            self::$_map[$class] = $map;
        }
    }

我们可以看到,执行addMap()就会给这个类的私有属性$_map[$class]添加成员,而且从autoload()方法代码执行顺序来看,是先加载类库映射的。

  • 获取类文件所属目录
    如果不存在类库映射,tp将自己去搜索这个类的路径,首先我们要知道这个常量 LIB_PATH,这个常理是在框架的入口文件中定义的(ThinkPHP/ThinkPHP.php) :
defined('LIB_PATH') or define('LIB_PATH', realpath(THINK_PATH . 'Library') . '/'); // 系统核心类库目录

tp的自动加载就是以这个常量所定义的路径作为参照点的,这个常量里面又包含另外一个THINK_PATH常量,这个常量是这样定义的

defined('THINK_PATH') or define('THINK_PATH', __DIR__ . '/');

这样LIB_PATH这个常量就是指的你的框架Library目录下面了。明白这个常量的含义后我们在回到tp的autoload()这个方法中:首先判断传入的类名有没有’\’(注意,第一个’\’是转义符),如果有,获取‘\’前面的字符,判断是不是Library下面目录,如果是,这个类文件的目录就是LIB_PATH这个常量所指的目录。现在有一个疑问?为什么传入的类名‘/’前面的字符可以实现路径的查找呢?其实这就和tp命名空间的规范很有关系了,因为在tp中,命名空间的名字和当前文件的所在相对目录是一致的,打个比方:
比如说现在的Think.class.php的目录是在 :“ThinkPHP/Library/Think/”下面,那么这个类所在的命名空间就是“Think”,假如我们尝试在Home/Index/index实例一个图像类,并且在自动加载函数里打印tp自动加载的类库,首先实例化图像类

这里写图片描述

我们知道,new Image()是Think命名空间下的,这个名称是非限定名称,编译是相当于是 new Think\Image() ,我们可以在加载方法中打印来看:

     // 检查是否存在映射
        if (isset(self::$_map[$class])) {
            include self::$_map[$class];
        } elseif (false !== strpos($class, '\\')) {
            echo $class."<hr/>";   //打印加载类文件
            $name = strstr($class, '\\', true);
            if (in_array($name, array('Think', 'Org', 'Behavior', 'Com', 'Vendor')) || is_dir(LIB_PATH . $name)) {
           ........................

打印已自动加载类
传过来的Think/Image这个类 ‘/’ 的前面的命名空间其实就是当前类所在的相对位置,所有tp通过这个命名空间来定位(命名空间根空间和目录一致)。
源码读到下面我就有点懵逼了……..

 if (in_array($name, array('Think', 'Org', 'Behavior', 'Com', 'Vendor')) || is_dir(LIB_PATH . $name)) {
                // Library目录下面的命名空间自动定位
                $path = LIB_PATH;
            } else {
                // 检测自定义命名空间 否则就以模块为命名空间
                $namespace = C('AUTOLOAD_NAMESPACE');
                $path      = isset($namespace[$name]) ? dirname($namespace[$name]) . '/' : APP_PATH;
            }

这个

 $namespace = C('AUTOLOAD_NAMESPACE');

我实在没找到是在哪里配置的,换句话讲,跑到Library目录以外怎么去自动加载就不知道了,先留个坑在这里以后来填,有知道的博友希望能够不吝赐教,感激不尽!

(残次文还是发表了吧………)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值