IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> laravel生命周期之初识Container -> 正文阅读

[PHP知识库]laravel生命周期之初识Container

提到laravel框架,我的脑海中最先浮现的是什么呢?那一定是,依赖注入、控制反转。作为后来居上的框架,laravel能取得如此的成绩,优秀的思想也贡献了很大一部分力量。

什么是Container?

定义:

那么在提到依赖注入之前我们就不得不先说一说一切的根本:容器Container。所谓容器,听名字就知道,是一个仓库,装东西用的,所以,container所有的功能,都围绕一个主题:管理类。

工作流程:

首先,生成一个数组绑定列表,用自定义名称作为主键,然后键值是闭包(输入的可能是闭包或者实体类,但是,在存储的时候,都统一转化成了闭包存储)。
其次,根据绑定列表,生成对应的类的实例,供用户使用,调用的时候,发现如果已经生成,不需要重新生成使用,实际上,Container就是类的一个仓库,以及缓存。
在laravel中Container的实现类为\Illuminate\Container\Container,该类提供了多个操作类的方法。
在这里插入图片描述
Container位于…/vendor/laravel/framework/src/Illuminate/Container/Container.php中,接下来我们来看下其常用方法(因版本不同,源码可能略有偏差,如果问题,欢迎留言指正!!!

别名函数:

	/**
     * 此方法会给abstract类设置一个alias别名
     */
    public function alias($abstract, $alias)
    {
        $this->aliases[$alias] = $abstract;

        $this->abstractAliases[$abstract][] = $alias;
    }
    /**
    *此方法会获取abstract的别名,如果abstract本身为别名则直接返回
    **/
    public function getAlias($abstract)
    {
        if (! isset($this->aliases[$abstract])) {
            return $abstract;
        }

        if ($this->aliases[$abstract] === $abstract) {
            throw new LogicException("[{$abstract}] is aliased to itself.");
        }

        return $this->getAlias($this->aliases[$abstract]);
    }
    /**
    *判断$name是否为别名
    **/
    public function isAlias($name)
    {
        return isset($this->aliases[$name]);
    }

isBuildable函数:

用来判断指定类型是否可构建(实例化)。满足二者之一则可实例化:实际类型是Closure或者实际类型与抽象类型名称相同(其实就是普通的类名称,非抽象类和接口)

protected function isBuildable($concrete, $abstract)
{
    return $concrete === $abstract || $concrete instanceof Closure;
}

容器绑定函数:bind、singleton

singleton是单例的,是bind函数share的一个应用。

public function bind($abstract, $concrete = null, $shared = false)
    {
        // 删除所有陈旧的实例和别名
        $this->dropStaleInstances($abstract);
		//如果$concrete为null,则认为$abstract为可类名称
        if (is_null($concrete)) {
            $concrete = $abstract; 
        }

        // 如果concrete不是闭包,则手动创建闭包
        if (! $concrete instanceof Closure) {
            $concrete = $this->getClosure($abstract, $concrete);
        }
		//注册绑定。实际就是放到bindings数组中
        $this->bindings[$abstract] = compact('concrete', 'shared');

        // 如果abstract已解析,则重新注册回调,可以通过毁掉的方式更新已注册的实例
        if ($this->resolved($abstract)) {
            $this->rebound($abstract);
        }
    }

实例化函数:make

make函数会自动完成类依赖的注入。

public function make($abstract, array $parameters = [])
{
	//获取类别名
	$abstract = $this->getAlias($this->normalize($abstract));
	//如果是单例则直接返回
	if (isset($this->instances[$abstract])) {
	   return $this->instances[$abstract];
    }
    //获取给定抽象的具体类型(这里自己其实也有点迷糊,欢迎大佬指正)
	$concrete = $this->getConcrete($abstract);
	// 实例化对象,递归调用(make类A时自动注入类B其实就是在这里实现的)
	if ($this->isBuildable($concrete, $abstract)) {
	$object = $this->build($concrete, $parameters);
	    } else {
	$object = $this->make($concrete, $parameters);
	    }
	//执行类的扩展。并将他们应用于正在构建的对象
	foreach ($this->getExtenders($abstract) as $extender) {
	$object = $extender($object, $this);
	    }
	//如果为singleton单例模式则保存实例化的对象到单例instances数组
	if ($this->isShared($abstract)) {
		$this->instances[$abstract] = $object;
	}
	//触发类型解析回调
	$this->fireResolvingCallbacks($abstract, $object);
	//标记实例为已解析
	$this->resolved[$abstract] = true;
	//返回实例化对象
	return $object;
}

实例化函数:build

用来实例化指定类型的对象,等同于直接new 对象,只不过这个操作有容器来完成

public function build($concrete, array $parameters = [])
{
//如果类型为闭包,则直接执行该闭包并返回
if ($concrete instanceof Closure) {
	return $concrete($this, $parameters);
}
$reflector = new ReflectionClass($concrete);
// 如果对象类型不可实例化,则抛出异常
if (! $reflector->isInstantiable()) {
if (! empty($this->buildStack)) {
$previous = implode(', ', $this->buildStack);
$message = "Target [$concrete] is not instantiable while building [$previous].";
        } else {
$message = "Target [$concrete] is not instantiable.";
        }
throw new BindingResolutionException($message);
    }
$this->buildStack[] = $concrete;
$constructor = $reflector->getConstructor();
// If there are no constructors, that means there are no dependencies then
// we can just resolve the instances of the objects right away, without
// resolving any other types or dependencies out of these containers.
if (is_null($constructor)) {
        array_pop($this->buildStack);
return new $concrete;
    }
$dependencies = $constructor->getParameters();
// Once we have all the constructor's parameters we can create each of the
// dependency instances and then use the reflection instances to make a
// new instance of this class, injecting the created dependencies in.
$parameters = $this->keyParametersByArgument(
$dependencies, $parameters
    );
$instances = $this->getDependencies(
$dependencies, $parameters
    );
    array_pop($this->buildStack);
return $reflector->newInstanceArgs($instances);
}

接下来我们通过一些小例子来加深理解。

abstract class Animal
{
    abstract public function run();
}

class Fish extends Animal
{
    protected $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function run()
    {
        echo 'Fish run';
    }
}

class Pig extends Animal
{
    protected $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function run()
    {
        echo 'Pig run';
    }
}

class People
{
    protected $food;

    public function __construct(\Animal $food)
    {
        $this->food = $food;
    }

    public function eat()
    {
        $this->food->run();
    }
}

$object2 = new Fish('panda2'); // 传统方式:用new关键字实例化对象
echo $object2->getName(); // panda

$container = new \Illuminate\Container\Container();
$object = $container->build('Fish', ['panda']); // 用容器来实例化对象
// $object = $container->make('Fish', ['panda']); // 用容器来实例化对象,用make也是OK的
echo $object->getName(); // panda

$container->bind('Animal', 'Fish'); // 绑定抽象类 Animal 到 Fish 实现
$object3 = $container->make('Animal', ['goldfish']); // 此时实例化 Animal 则会返回 Pig 对象
echo $object3->run(); // Pig run

$container->flush();
$container->singleton('Animal', 'Fish'); // 绑定抽象类 Animal 到 Fish 实现,单例模式
$object4 = $container->make('Animal', ['goldfish']);
$object5 = $container->make('Animal', ['goldfish']); // 多次实例化返回的是同一个对象
var_dump($object4 === $object5); // true

$container->flush();
$container->bind('Animal', 'Fish'); // 绑定抽象类 Animal 到 Fish 实现
$people = $container->make('people'); // 实例化People,自动注入 $food 参数,无需手动实例化传入
$people->eat(); // Fish run

小结

本章节我们学历了laravel的容器及其常用的相关函数,希望对大家阅读源码有帮助,后续我们将继续对laravel源码进行学习,有兴趣的动动小手点个关注吧,感谢观看!

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章           查看所有文章
加:2021-11-22 12:08:09  更:2021-11-22 12:09:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/14 14:42:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码