参考资料:
laravel底层核心代码分析之核心概念讲解
PHP控制反转(IOC)和依赖注入(DI)
闭包匿名函数,还在傻傻搞不清楚吗?
Laravel框架核心
优点
- 集成了composer
- 实现了依赖注入,更好的管理类的依赖关系,方便扩展(相对于MVC模式)
- 高级特性:控制台console,事件event,队列queue,中间件middleware,门面模式facades
- 核心概念:服务容器 serviceProvider
缺点及优化
缺点
- 加载文件太多,访问速度慢
优化
- 缓存配置文件
- 去掉不必要的加载文件(主要是serviceProvider)
- 开启Opcache
框架启动流程(生命周期)
- 引用自动加载文件
- 生成服务容器
1) 注册基础的bingings
2) 通过bind注册服务容器,事件,路由,日志服务
3) 通过bind绑定接口 - 获取Request对象
- 逻辑处理
1) 解析启动项(基础服务)如路由,异常处理,门面,服务容器
2) 通过管道模式,用中间件过滤用户请求,处理业务逻辑 - 返回Response对象
知识点
单例模式,观察者模式,管道模式
依赖注入,匿名函数,反射
预定义接口ArrayAccess
控制反转和依赖注入
控制反转 IOC(inversion of control)
将组件间的依赖关系从程序内部提到外部来管理
解释:不在A类中直接新建B类实例,而是通过IOC容器将B类的实例传给A
依赖注入 DI(dependency injection)
将组件的依赖通过外部以参数或其他形式注入
示例:
class DbMysql
{
public function query(){}
}
class IOC
{
public $db;
public function __construct($dbMysql)
{
$this->db = $dbMysql;
}
public function action()
{
$this->db->query();
}
}
$db = new DbMysql();
$c = new IOC($db);
$c->action();
IOC类中不需要实例化DbMysql,而是将DbMysql的实例作为参数传入,仅调用DbMysql的方法。这种模式就是依赖注入。
将B类的实例化动作提出到IOC类的外面,就叫做控制反转。
PHP的反射机制
在PHP运行时,扩展分析程序,导出或提出关于类,方法,属性,参数的详细信息,这种动态获取和调用信息的功能称为反射API。
class A
{
public function __construct(B $b)
{
}
}
class B
{
}
//获取类的反射信息(所有信息)
$reflector = new ReflectionClass('A');
//获取构造函数
$constructor = $reflector->getConstructor();
//获取构造函数参数
$dependencies = $constructor->getParameters();
//获取依赖的类名
foreach ($dependencies as $dependency){
if(!is_null($dependency->getClass())){
$classname = $dependency->getClass()->name;
$p[] = new $classname();
}
}
//从给出的参数创建一个新的类实例
$a = $reflector->newInstanceArgs($p);
如果B类也有依赖的类,则需要通过递归创建
b = $b;
}
public function getB()
{
$this->b->bMethod();
}
}
class B
{
public function __construct(C $c,D $d)
{
$this->c = $c;
$this->d = $d;
}
public function bMethod()
{
echo "我是B中的方法bMethod()";
}
}
class C{
public function __construct()
{
}
public function cMethod(){
echo "我是C中的方法cMethod()";
}
}
class D{
public function __construct()
{
}
public function dMethod(){
echo "我是D中的方法dMethod()";
}
}
class Ioc
{
protected $instances = [];
public function __construct()
{
}
public function getInstance($classname){
$reflector = new ReflectionClass($classname);
$constructor = $reflector->getConstructor();
$dependencies = $constructor->getParameters();
if(!$dependencies){
return new $classname();
}
foreach ($dependencies as $dependency){
if(!is_null($dependency->getClass())){
$instances[] = $this->make($dependency->getClass()->name);
}
}
return $reflector->newInstanceArgs($instances);
}
public function make($classname){
return $this->getInstance($classname);
}
}
$ioc = new Ioc();
$a = $ioc->make('A');
$a->getB();
总结
PHP程序运行的本质:包含文件,获取实例化对象。
传统框架:通过include/require来管理类的依赖关系。
Laravel:通过namespace和use,实现了自动加载机制,找到类所在文件,然后通过反射获取类的实例化对象。
学习资料:
laravel底层核心代码分析之匿名函数
闭包匿名函数,还在傻傻搞不清楚吗?
匿名函数
回调函数
调用函数的时候将另一个函数作为参数传递到调用的函数中,而不是传递一个普通的变量作为参数
使用回调函数是为了可以将一段自己定义的功能传到函数内部使用
function test($v){
return $v * $v;
}
$a = array(1, 2, 3);
print_r(array_map("test", $a)); //[1, 4, 9]
匿名函数
没有名字的函数就是匿名函数
1.普通使用
$func = function($str){
echo $str;
};
$func('Hello');
2.使用use传递外部变量
$b = "World";
$func = function($str) use($b){
echo $str. " ". $b;
};
$func("Hello");
闭包(closures)
php的闭包(Closure)也就是匿名函数。是PHP5.3引入的。
闭包函数就是能够读取其他函数内部变量的函数
闭包 = 匿名函数 + use
function getMoney($a, $b){
return function($p) use ($a, $b){
echo $p. '-'. $a. '-'. $b;
};
}
$closure = getMoney('1', '2');
var_dump($closure instanceof Closure);//true
$closure('test');//test-1-2
实际应用
1. 当做回调函数
src/Illuminate/Routing/Router.php
public function gatherRouteMiddleware(Route $route)
{
$middleware = collect($route->gatherMiddleware())->map(function ($name) {
return (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups);
})->flatten();
return $this->sortMiddleware($middleware);
}
2. 当做闭包
src/Illuminate/Container/Container.php
//创建
protected function getClosure($abstract, $concrete)
{
return function ($container, $parameters = []) use ($abstract, $concrete) {
if ($abstract == $concrete) {
return $container->build($concrete);
}
return $container->make($concrete, $parameters);
};
}
//绑定
function bind($abstract, $concrete = null, $shared = false)
{
...
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
...
}
//调用
public function build($concrete)
{
if ($concrete instanceof Closure) {
return $concrete($this, $this->getLastParameterOverride());
}
...
}