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

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

     public function __get($name)
{
if (isset($this->helper[$name])) {
return $this->helper[$name];
}
$fun = $this->autoload_class;
$class_name = $fun($name);
unset($fun);
if ($class_name!==false){
$this->helper[$name] = new $class_name;
return $this->helper[$name];
}
throw new Exception($this->lang('class_not_found').$name);
}

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

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

YiluPHP是如何做到不用配置、不用注入就能直接使用所有的类?的更多相关文章

  1. spring中bean配置和注入场景分析

    bean与spring容器的关系 Bean配置信息定义了Bean的实现及依赖关系,Spring容器根据各种形式的Bean配置信息在容器内部建立Bean定义注册表,然后根据注册表加载.实例化Bean,并 ...

  2. ASP.NET Core 在 JSON 文件中配置依赖注入

    前言 在上一篇文章中写了如何在MVC中配置全局路由前缀,今天给大家介绍一下如何在在 json 文件中配置依赖注入. 在以前的 ASP.NET 4+ (MVC,Web Api,Owin,SingalR等 ...

  3. Spring boot将配置属性注入到bean类中

    一.@ConfigurationProperties注解的使用 看配置文件,我的是yaml格式的配置: // file application.yml my: servers: - dev.bar.c ...

  4. Spring4学习笔记二:Bean配置与注入相关

    一:Bean的配置形式 基于XML配置:在src目录下创建 applicationContext.xml  文件,在其中进行配置. 基于注解配置:在创建bean类时,通过注解来注入内容.(这个不好,因 ...

  5. Springboot学习笔记(六)-配置化注入

    前言 前面写过一个Springboot学习笔记(一)-线程池的简化及使用,发现有个缺陷,打个比方,我这个线程池写在一个公用服务中,各项参数都定死了,现在有两个服务要调用它,一个服务的线程数通常很多,而 ...

  6. Spring boot将配置属性注入到bean 专题

    https://blog.csdn.net/wangmx1993328/article/details/81002901 Error starting ApplicationContext. To d ...

  7. spring_入门配置和注入

    Spring的获取容器: public static void main(String[] args) { //获取核心容器 BeanFactory延迟加载对象 ApplicationContext ...

  8. 转载:ASP.NET Core 在 JSON 文件中配置依赖注入

    在以前的 ASP.NET 4+ (MVC,Web Api,Owin,SingalR等)时候,都是提供了专有的接口以供使用第三方的依赖注入组件,比如我们常用的会使用 Autofac.Untiy.Stri ...

  9. 外部配置属性值是如何被绑定到XxxProperties类属性上的?--SpringBoot源码(五)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接 SpringBoot是如何实现自动配置的?--SpringBoot源码(四) 温故而知新,我们来简单回顾一下上 ...

  10. idea下使用autowire注解注入对象,结果初始化不到类

    如果idea下使用autowire注解注入对象,结果初始化不到类,明明使用快捷键alt+insert是可以找到该注入的对象的. 而我们在使用的时候,缺报错了??? 注意,当我们在注入对象的时候,我们留 ...

随机推荐

  1. pdf 在线预览之 pdfjs插件

    这个插件不需要阅读器 也不会屏蔽签章 但是也是兼容到ie11

  2. Java多线程——线程间通信

    Java多线系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线 ...

  3. C#取视频某一帧图片

    首先下载 ffmpeg http://ffmpeg.org/ 注意一定要从官网下载,其他地方可以会有问题 解压后在 bin 目录下找到 ffmpeg.exe 用到的使命是 -i 视频地址 -ss 第几 ...

  4. 02 jQuery中的事件、动画、复合函数

    jQuery中的事件 在JavaScript中,常用的基础事件有鼠标事件.键盘事件.window事件.表单事件.事件绑定和处理函数的语法格式如下 语法q 事件名 = "函数名()" ...

  5. 构建调试Linux内核网络代码的环境MenuOS系统

    构建MenuOS系统 1.将指定文件拷贝到本地: git clone https://github.com/mengning/linuxnet.git 此过程可能需要输入github账号和密码. 2. ...

  6. No provider available for the service com.xxx.xxx 错误解决

    HTTP Status 500 - Servlet.init() for servlet springmvc threw exception type Exception report message ...

  7. java 抽象类和接口整理

    java中定义一些不含方法体的方法,方法体的实现交给该类的子类根据自己的具体情况去实现,这样的方法就是abstract修饰的抽象方法,包含抽象方法的类叫抽象类,用abstract修饰 抽象方法: ab ...

  8. 2019-2020-2 20199317《Linux内核原理与分析》第二周作业

    第一章   计算机工作原理 1   存储程序计算机工作模型      存储程序计算机的主要思想是将程序存放在计算机存储器中,然后按存储器中的存储程序的首地址执行程序的第一条指令,以后就按照该程序中编写 ...

  9. 图的存储结构与操作--C语言实现

    图(graph)是一种比树结构还要复杂的数据结构,它的术语,存储方式,遍历方式,用途都比较广,所以如果想要一次性完成所有的代码,那代码会非常长.所以,我将分两次来完成图的代码.这一次,我会完成图的五种 ...

  10. Docker简介与安装

    简介与安装 简介 Docker是什么 一款产品从开发到上线,从操作系统,到运行环境,再到应用配置.作为开发+运维之间的协作我们需要关心很多东西,这也是很多互联网公司都不得不面对的问题,特别是各种版本的 ...