Laravel底层学习笔记01 - 框架核心,依赖注入,闭包

IT小马
English

参考资料:
laravel底层核心代码分析之核心概念讲解
PHP控制反转(IOC)和依赖注入(DI)
闭包匿名函数,还在傻傻搞不清楚吗?

Laravel框架核心

优点

  1. 集成了composer
  2. 实现了依赖注入,更好的管理类的依赖关系,方便扩展(相对于MVC模式)
  3. 高级特性:控制台console,事件event,队列queue,中间件middleware,门面模式facades
  4. 核心概念:服务容器 serviceProvider

缺点及优化

缺点

  1. 加载文件太多,访问速度慢

优化

  1. 缓存配置文件
  2. 去掉不必要的加载文件(主要是serviceProvider)
  3. 开启Opcache

框架启动流程(生命周期)

  1. 引用自动加载文件
  2. 生成服务容器
    1) 注册基础的bingings
    2) 通过bind注册服务容器,事件,路由,日志服务
    3) 通过bind绑定接口
  3. 获取Request对象
  4. 逻辑处理
    1) 解析启动项(基础服务)如路由,异常处理,门面,服务容器
    2) 通过管道模式,用中间件过滤用户请求,处理业务逻辑
  5. 返回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类也有依赖的类,则需要通过递归创建

<?php 
class A
{
    public function __construct(B $b)
    {
        $this->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());
        }
        ...
    }

注意事项

1. 匿名函数只有在调用的时候才会真正解析
2. 调用匿名函数时需要传递function后面的参数
阅读 546

IT小马の菜园
IT菜鸟的学习博客

版本控制:git

1k 声望
19 粉丝
0 条评论

版本控制:git

1k 声望
19 粉丝
文章目录
宣传栏