Laravel Facade的加载过程及原理
Facades(读音:/fəˈsäd/ )为应用程序的
服务容器
中可用的类提供了一个「静态」接口。你不必use
一大串的命名空间,也不用实例化对象,就能访问对象的具体方法。
use Config;class Test
{public function index(){return Config::get('app.name');}
}
Facade 的启动与注册
Facade 的启动引导是在 Illuminate\Foundation\Bootstrap\RegisterFacades
中注册的。
public function bootstrap(Application $app)
{Facade::clearResolvedInstances();Facade::setFacadeApplication($app);AliasLoader::getInstance(array_merge($app->make('config')->get('app.aliases', []),$app->make(PackageManifest::class)->aliases()))->register();
}
默认的别名配置是从
app
配置文件下的aliases
读取的,PackageManifest
是laravel 5.5
新增的包自动发现
规则,这里我们暂时不考虑PackageManifest
包提供的别名。
其中,array_merge
返回如下格式的数组:
"App" => "Illuminate\Support\Facades\App""Artisan" => "Illuminate\Support\Facades\Artisan""Auth" => "Illuminate\Support\Facades\Auth""Blade" => "Illuminate\Support\Facades\Blade"...
上面代码将通过 AliasLoader
把所有的 facade
注册进自动加载。其核心就是 php
的 spl_autoload_register
。
/*** Prepend the load method to the auto-loader stack.** @return void*/protected function register(){if (! $this->registered) {spl_autoload_register([$this, 'load'], true, true);$this->registered = true;}}
注册完成后,后续所有 use
的类都将通过 load
函数来完成类的自动加载。
注意,这里在定义
spl_autoload_register
时,最后面的参数传的是true
。当该参数是true
时,spl_autoload_register()
会添加函数到队列之首,而不是队列尾部。(优先通过该函数来完成自动加载)
也就是说,
<?phpuse Config;
use App\User;class Test
{public function index(){Config::get('app.name');new User();}
}
不管我们 use
的是具体存在的类(App\User
)还是别名 (Config)
,都将最先通过 load
函数来完成自动加载,当该函数返回 false
时,再由其他自动加载函数来完成自动加载(如 composer psr-4
)。
在 AliasLoader
的 load
方法中,主要是用了 class_alias
函数来实现的别名自动加载。
public function load($alias)
{if (isset($this->aliases[$alias])) {return class_alias($this->aliases[$alias], $alias);}
}
关于 class_alias
这里帖一个官方的列子:
class foo { }class_alias('foo', 'bar');$a = new foo;
$b = new bar;// the objects are the same
var_dump($a == $b, $a === $b); //true
var_dump($a instanceof $b); //false// the classes are the same
var_dump($a instanceof foo); //true
var_dump($a instanceof bar); //truevar_dump($b instanceof foo); //true
var_dump($b instanceof bar); //true
Facade 的加载
当我们在使用 Facade
时,如:
<?phpuse Config;class Test
{public function index(){Config::get('app.name');}
}
实际上加载的是 Illuminate\Support\Facades\Config
类(因为我们已经注册了 class_alias
),相当于:
<?phpuse Illuminate\Support\Facades\Config;class Test
{public function index(){Config::get('app.name');}
}
而所有的 Facade
都继承自 Illuminate\Support\Facades\Facade
类,在该基类中定义了一个 __callStatic
方法,已至于我们能够轻松地使用 Facade
(不用实列化)。
<?phppublic static function __callStatic($method, $args)
{$instance = static::getFacadeRoot();if (! $instance) {throw new RuntimeException('A facade root has not been set.');}return $instance->$method(...$args);
}
getFacadeRoot
方法用于获取别名类的具体实列,我们知道,所有的 Facade
类都需要定义一个 getFacadeAccessor
方法。该方法可能的返回值有:
- String 类型的字符串(如
config
,db
) - String 类型的类字符串 (如
App\Service\SomeService
) - Object 具体的实列化对象
- Closure 闭包
如 Config Facade
的 getFacadeAccessor
方法如下:
protected static function getFacadeAccessor()
{return 'config';
}
getFacadeRoot
方法将根据 getFacadeAccessor()
的返回值,从容器从取出对应的实列对象。
public static function getFacadeRoot()
{$name = static::getFacadeAccessor();if (is_object($name)) {return $name;}if (isset(static::$resolvedInstance[$name])) {return static::$resolvedInstance[$name];}return static::$resolvedInstance[$name] = static::$app[$name];
}
由于 APP 容器中已经注册过 config
的实列
<?php
//Illuminate\Foundation\Bootstrap/LoadConfiguration$app->instance('config', $config = new Repository($items));
所以 \Config::get('app.name', 'dafault)
实际访问的是 Repository
实列的 get('app.name', 'default')
方法。
参考文献:
https://segmentfault.com/a/1190000011274118
Laravel Facade的加载过程及原理相关推荐
- Window7系统的完整开机加载过程的原理和机制
1.开启电源 计算机系统将进行加电自检(POST).如果通过,之后BIOS会读取主引导记录(MBR)--被标记为启动设备的硬盘的首扇区,并传送被Windows 7建立的控制编码给MBR.这时,Wind ...
- java虚拟机学习(四)类的加载过程
2019独角兽企业重金招聘Python工程师标准>>> 类从虚拟机内存加载到从内存卸载,经历的生命周期是:加载,验证,准备,解析,初始化,使用,卸载这几个阶段, 其中验证,解析,初始 ...
- 面试官:讲讲Spring框架Bean的加载过程
spring作为目前我们开发的基础框架,每天的开发工作基本和他形影不离,作为管理bean的最经典.优秀的框架,它的复杂程度往往令人望而却步. 不过作为朝夕相处的框架,我们必须得明白一个问题就是spri ...
- JVM源码阅读-本地库加载流程和原理
前言 本文主要研究OpenJDK中JVM源码中涉及到native本地库的加载流程和原理的部分.主要目的是为了了解本地库是如何被加载到虚拟机,以及是如何找到并执行本地库里的本地方法,以及JNI的 JNI ...
- JVM学习笔记之-类加载子系统,类的加载与类的加载过程,双亲委派机制
一 类加载器与类加载过程 类加载子系统作用 类加载器子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识. ClassLoader只负责class文件的加载,至于 ...
- JVM从入门到精通(三):热加载的实现原理,Java内存模型,缓存行,指令重排,合并写技术等
上节回顾:类加载机制 双亲委派机制 parent只是一个成员变量,不是继承关系. 上节课的遗留问题 parent是怎么指定的? 手动指定parent: 双亲委派机制可以被打破吗? 双亲委派机制是在Cl ...
- 中yeti不能加载_第二十章_类的加载过程详解
类的加载过程详解 概述 在 Java 中数据类型分为基本数据类型和引用数据类型.基本数据类型由虚拟机预先定义,引用数据类型则需要进行类的加载 按照 Java 虚拟机规范,从 Class 文件到加载到内 ...
- 你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)
转http://www.cnblogs.com/zhijianliutang/p/4100103.html 前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的 ...
- Trembling ! Java类的加载过程详解(加载验证准备解析初始化使用卸载)
[1]类的生命周期 一个类从加载进内存到卸载出内存为止,一共经历7个阶段: 加载->验证->准备->解析->初始化->使用->卸载 其中,类加载包括5个阶段: 加载 ...
最新文章
- 《UNIXLinux程序设计教程》一3.7 非阻塞I/O
- 数据中心冷热空气流控制优化方案
- [MATLAB学习笔记]clf清空图窗1013(1)
- 为什么Redux需要reducer成为“纯函数”
- WebRTC促进跨平台指挥调度,触发安防应用新创意
- mongodb 速成笔记
- 《Summer Tree》第八期封面
- 16复变函数的积分(二)
- python基础代码大全-Python基础汇总
- 信息系统项目管理笔记
- 数据挖掘概念与技术第三版 范明、孟晓峰译 第三章习题答案
- 白话大数据与机器学习——阅读笔记
- 戴尔计算机无法安装Win10,dell电脑安装win10 识别不了硬盘
- 修改bios密码 服务器,为BIOS设置密码让我们的系统更加安全
- VI设计创意的方法与技巧
- 基于java+ssm+mysql的医院管理系统
- ubuntu20.04 root用户 登录桌面 / kubuntu20.04 root用户 登录桌面
- Java媒体框架(JMF)资料
- 【00】processing-历史(中文)
- Windows 系统错误193: 0xc1
热门文章
- FizzBuzz(二)
- 多渠道推广场景下,如何实现 App 用户增长的精准归因?
- 《Mastering the game of Go with deep neural networks and tree search》解读
- 法国程序员没有“996” 40多岁最受人尊敬
- VM16虚拟机去虚拟化心得3(干货来了)
- STM32移相全桥电源方案
- RecyclerView 横向滑动
- Federated Learning of Multi-branch Networks from Periodically Shifting Distributions
- python 素描化图像_任意图像转素描:Python分分钟实现
- 华为s5735交换机配置ssh远程登陆