码迷,mamicode.com
首页 > Web开发 > 详细

YiluPHP是如何做到不用配置、不用注入就能直接使用所有的类?

时间:2019-12-20 18:35:28      阅读:72      评论:0      收藏:0      [点我收藏+]

标签:目录   函数   自身   code   Once   iss   mod   逻辑   变量   

使用过YiluPHP的人都会发现,不管是模型类还是逻辑类、辅助类还是工具类,使用所有类都不需要在配置文件中设置加载或注入,也不需要在页面中使用 include 或 require 或 use ,直接使用   $app->类名->方法名()   就可以了,这个机制如此方便,刚开始使用的人都会有点不知得措,担心自己是不是做错了什么?我现在告诉你,你没有少做啥,也没有做错啥,YiluPHP就是这样设计的,下面我来告诉你YiluPHP是如何做到的。

有人可能会想使用 spl_autoload_register() 函数就能做到, spl_autoload_register() 函数可以注册任意数量的自动加载器,比如第三方库中的,要找一个类需要遍历所有的自动加载器,效率很低,这不符合YiluPHP追求速度的原则。YiluPHP的 $app 是一个全局变量,是名为YiluPHP的类的实例,这个类使用了php的魔术方法 __get,代码如下:

 1     public function __get($name)
 2     {
 3         if (isset($this->helper[$name])) {
 4             return $this->helper[$name];
 5         }
 6         $fun = $this->autoload_class;
 7         $class_name = $fun($name);
 8         unset($fun);
 9         if ($class_name!==false){
10             $this->helper[$name] = new $class_name;
11             return $this->helper[$name];
12         }
13         throw new Exception($this->lang(‘class_not_found‘).$name);
14     }

当使用   $app->类名->方法名()   时,会先从$app的helper属性中查找是否已经有对应的类实例(helper属性是一个容器,装有所有已经使用过的类实例,所以当同一个类被第二次使用时不会再去查找文件,也不会再做实例化操作,直接从helper容器中返回,helper容器的设计也是YiluPHP运行迅速的原因之一),若在容器找不到对应的类实例,会调用自身的 autoload_class() 函数查找文件,autoload_class() 函数是赋值给$app的一个属性的,它的实现在$app的初始化函数 __construct() 中,

 1     public function __construct()
 2     {
 3         $this->autoload_class = function ($class_name){
 4             $file = $GLOBALS[‘project_root‘].‘helper/‘.$class_name.‘.php‘;
 5             if (file_exists($file)) {
 6                 //helper类文件的文件名、类名、app中的调用方法三者需要一致
 7                 require_once($file);
 8                 return $class_name;
 9             }
10 
11             //将驼峰式的名称用下划线分割
12             $path = preg_replace(‘/(?<=[a-z])([A-Z])/‘, ‘_$1‘, $class_name);
13             $path = explode(‘_‘, $path, 2);
14             $path = $path[0].‘/‘.$class_name;
15             $file = $GLOBALS[‘project_root‘].$path.‘.php‘;
16             if (file_exists($file)) {
17                 //类文件的文件名、类名、app中的调用方法三者需要一致
18                 require_once($file);
19                 return $class_name;
20             }
21 
22             //支持给类取别名
23             if(!empty($GLOBALS[‘config‘][‘helper_alias‘]) && array_key_exists($class_name, $GLOBALS[‘config‘][‘helper_alias‘]) ){
24                 $real_class_name = $GLOBALS[‘config‘][‘helper_alias‘][$class_name];
25                 $file = $GLOBALS[‘project_root‘].‘helper/‘.$real_class_name.‘.php‘;
26                 if (file_exists($file)) {
27                     require_once($file);
28                     return $real_class_name;
29                 }
30 
31                 //将驼峰式的名称用下划线分割
32                 $path = preg_replace(‘/(?<=[a-z])([A-Z])/‘, ‘_$1‘, $real_class_name);
33                 $path = explode(‘_‘, $path, 2);
34                 $path = $path[0].‘/‘.$real_class_name;
35                 $file = $GLOBALS[‘project_root‘].$path.‘.php‘;
36                 if (file_exists($file)) {
37                     require_once($file);
38                     return $real_class_name;
39                 }
40             }
41             return false;
42         };
43     }
autoload_class() 函数先去helper目录中查找类文件,若找不到,再根据类名前缀单词去相应的目录查找类文件(这中间还省略了根据类的别名查找的流程),再找不到就抛出『找不到类』的异常。其实最早作者打算把所有的类文件都存放在helper目录中的,这是为了减少程序执行流程,从而提升框架的运行速度。但是考虑以下两个方面的原因,还是决定支持划分目录存放类:
第一,如果系统功能太多,类文件也多,写代码时定位类文件困难,虽然当系统功能太多时,最好的选择是将大系统拆分小系统,分别部署分散压力,但是很多创业性公司因需求变化快,也很容易造成文件太多;
第二,按功能不同把类文件存放在不同的目录,已经成为几乎所有程序员结构化思维习惯,顺应这个习惯可以让程序员更快的适应YiluPHP框架。
除了分目录存放的习惯保留了之外,还有命名的习惯也兼容了『下划线连接单词』和『驼峰式』两种命名规则,因此一个model类,即可以这样命名 model_user,也可以这样命名 modelUser,都是可以自动识别的。
下面是一个类的方法被调用的流程图

技术图片

YiluPHP是如何做到不用配置、不用注入就能直接使用所有的类?

标签:目录   函数   自身   code   Once   iss   mod   逻辑   变量   

原文地址:https://www.cnblogs.com/yiluphp/p/yiluphp_how_to_autoload_class.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!