thinkphp自动加载机制

PHP的自动加载机制个人感觉使用起来还是很方便的。关于PHP的自动加载机制,其核心的方法是__autoload()和spl_autoload_register()两个函数。

在PHP5之后,当加载PHP类的时候,如果该类所在的文件没有被包含的话,Zend引擎会自动去调用__autoload()函数。当然,此函数必须由用户来实现。否则的话系统就会报错——找不到该类。

function __autoload($class_name) { require_once ($class_name . “class.php”); } $memo= new Onmpw();

通过以上的例子,我们可以看出__autoload()在这个过程中做了三件事。第一、根据类名来确定类所在的文件名;第二、确定类文件所在的磁盘路径;第三、将类从磁盘文件中加载到系统中。其中最主要的还是第一和第二步。必须在开发中约定类名与磁盘文件的映射方法,只有这样我们的系统才能找到类名对应的磁盘文件从而将其加载到系统中。

但现在问题来了,假如在一个系统的实现中,假如需要使用很多其它的类库,这些类库可能是由不同的开发工程师开发,其类名与实际的磁盘文件的映射规则不尽相 同。这时假如要实现类库文件的自动加载,就必须在__autoload()函数中将所有的映射规则全部实现,因此__autoload()函数有可能会非常复杂,甚至无法实现。最后可能会导致__autoload()函数十分臃肿,这时即便能够实现,也会给将来的维护和系统效率带来很大的负面影响。还有一个问题就是__autoload()函数只能使用一次。在你的项目中使用了__autoload()函数,当你引用了其它的项目,在你引用的项目中也有一个__autoload()函数,这样两个函数就会有冲突。

因此,PHP5给我们提供了spl_autoload_register()函数来避免上述的问题。spl_autoload_register()函数允许我们自己定义自动加载函数。

PHP在实例化一个对象时(实际上在实现接口,使用类常数或类中的静态变量,调用类中的静态方法时都会如此),首先会在系统中查找该类(或接口)是否存在,如果不存在的话 尝试使用autoload机制来加载该类。而autoload机制的主要执行过程为:

(1) 检查执行器全局变量函数指针autoload_func是否为NULL。 (2) 如果autoload_func==NULL, 则查找系统中是否定义有__autoload()函数,如果没有,则报告错误并退出。 (3) 如果定义了__autoload()函数,则执行__autoload()尝试加载类,并返回加载结果。 (4) 如果autoload_func不为NULL,则直接执行autoload_func指针指向的函数用来加载类。

注意此时并不检查__autoload()函数是否定义。

也就是说:使用了spl_autoload_register()函数之后,当我们加载类的时候,系统首先会检查是否注册了自定义的自动加载函数。如果没有定义,系统会调用__autoload()函数(前提是我们事先了__autoload()函数)。如果自定义了自动加载函数,系统就会使用自定义的加载函数加载类。

function classLoader($class_name) { require_once ($class_name . “class.php”); } spl_autoload_register('classLoader'); $obj = new Onmpw();

如果使用spl_autoload_register()函数注册了自动加载函数,但是没有找到我们需要实例化的类。此时,即使我们实现了__autoload()函数,该函数也不会执行。

好了,简单的介绍了spl_autoload_register()和__autoload()这两个函数以后,下面我们再简单分析一下ThinkPHP中的自动加载机制。

ThinkPHP的自动加载机制的实现是在Think.class.php中

static public function start() { // 注册AUTOLOAD方法 spl_autoload_register('Think\Think::autoload'); // 设定错误和异常处理 register_shutdown_function('Think\Think::fatalError'); …… }

我们看,在启动方法start()中使用了spl_autoload_register();方法注册了自定义的加载类库的函数。

在autoload()函数中,是检测是否有类和类文件的映射,如果有映射,那么直接导入文件即可。

if(isset(self::$_map[$class])) { include self::$_map[$class]; }

当然,如果没有映射,那就需要进行其他的分析。ThinkPHP类文件映射的注册函数如下

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

接下来就是查看是否使用了命名空间。如果使用了命名空间,查看其命名空间的有效性,否则的话就检测自定义的命名空间。最后如果二者都不是的话就以模块为命名空间

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; }

最后如果没有开启命名空间的使用,那加载还是比较简单的。首先是加载类库层,如果加载成功,那直接结束该函数的运行。

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 ; }

我们注意到,在上面的代码中有C('APP_AUTOLOAD_PATH')。该选项APP_AUTOLOAD_PATH是在配置文件中进行配置的

'APP_AUTOLOAD_PATH' => '', //该项有效的前提是关闭APP_USE_NAMESPACE 'APP_USE_NAMESPACE' => false, // 应用类库是否使用命名空间

对于ThinkPHP的自动加载机制就介绍这么多。

本文分享自微信公众号 - Tech爬虫(php_pachong),作者:爬虫

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-02-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 模型技术 - 数据库连接

    在使用模型操作之前,我们首先创建一个数据库:thinkphp。创建一个用户表:user。添加一些数据即可。 ThinkPHP 内置了抽象数据库访问层,把不同的数...

    公众号php_pachong
  • MySQL配置、使用规范

    一、表名 和 数据库名 不要用大小写混合(即驼峰式),应该全部用小写,使用下划线作为连接符。

    公众号php_pachong
  • 售前评估的工作量和项目经理评估的有出入,怎么办?

    场景:昨天同事H和我沟通,谈到了项目在开展时存在的问题,聊到公司的工作量评估和考核办法。目前工作量在售前的时候,由售前人员评估后经过部门经理的审阅,和业主客户进...

    公众号php_pachong
  • 在R中使用支持向量机(SVM)进行数据挖掘

    在R中,可以使用e1071软件包所提供的各种函数来完成基于支持向量机的数据分析与挖掘任务。请在使用相关函数之前,安装并正确引用e1071包。该包中最重要的一个函...

    机器学习AI算法工程
  • SVM的R语言实战

    在R中,可以使用e1071软件包所提供的各种函数来完成基于支持向量机的数据分析与挖掘任务。请在使用相关函数之前,安装并正确引用e1071包。该包中最重要的一个函...

    智能算法
  • swift之函数式编程

    最近初学swift,和OC比,发现语言更现代,也有了更多的特性。如何写好swift代码,也许,熟练使用新特性写出更优秀的代码,就是答案。今天先从大的方向谈谈sw...

    王大锤
  • PHP SPL扩展简单使用

    这是一个自动加载函数,在PHP5中,当我们实例化一个未定义的类时,就会触发此函数。看下面例子:

    叫我可儿呀
  • Spring data 相关注解

    作用是json序列化时将Java bean中的一些属性忽略掉,序列化和反序列化都受影响。

    吐吐吐吐吐葡萄皮
  • 面试:ZooKeeper二十三连问,看看你能不能接住

    ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,它是集群的管理者,监视着集群中各个节点的状态根据...

    IT大咖说
  • 一次生产事故的优化经历

    老七Linux

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动