TP5.1 源码窥探之容器面纱

在了解了单例模式,注册树模式和反射机制以后,下面来了解下容器类

容器类

项目入口文件index.php

Container::get('app')->run()->send();

系统自动加载Container容器类,然后调用get方法

thinkphp/library/think/Container.php

public static function get($abstract, $vars = [], $newInstance = false)
{
    return static::getInstance()->make($abstract, $vars, $newInstance);
}

可以看到容器类首先实例化,然后调用make方法,携带的参数是app,[],false,然后进入make方法

thinkphp/library/think/Container.php

 public function make($abstract, $vars = [], $newInstance = false)
{
    if (true === $vars) {
        // 总是创建新的实例化对象
        $newInstance = true;
        $vars        = [];
    }
    $abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;

    if (isset($this->instances[$abstract]) && !$newInstance) {
        return $this->instances[$abstract];
    }

    if (isset($this->bind[$abstract])) { //1 true   5 false
        $concrete = $this->bind[$abstract]; //2 think\App

        if ($concrete instanceof Closure) {
            $object = $this->invokeFunction($concrete, $vars);
        } else {
            $this->name[$abstract] = $concrete;//3 ['app'=>'think\App']

            return $this->make($concrete, $vars, $newInstance);//4 think\App,[],false
        }
    } else {
        $object = $this->invokeClass($abstract, $vars);//6 think\App,[]
    }

    if (!$newInstance) {
        $this->instances[$abstract] = $object;//7 ['think\App' => 'App实例对象']
    }

    return $object;
}

可以看到上边标注的步骤流程,最终将think\App实例放到注册池里面,反射类之前有分享过,就不再赘述了。

实践

写了一个不正规的容器类,因为设计的太简单了,不能满足复杂场景的应用,比如依赖注入,参数绑定,闭包等情况。

note/container/Container.php

namespace note\container;

use ReflectionClass;
use ReflectionMethod;

/**
 * Class Container
 * @package note\container
 */
class Container
{
    private static $instance = null;

    // 命名空间 => 实例
    private $instances = [];

    private function __construct()
    {
        //todo construct
    }

    /**
     * @return Container|null
     */
    public static function getInstance()
    {
        if( ! self::$instance instanceof self){
            self::$instance = new self;
        }
        return self::$instance;
    }

    /**
     * @param $key
     * @param array $vars
     * @return mixed|object
     * @throws \ReflectionException
     */
    public function get($key,$vars=[])
    {
        if(isset($this->instances[$key])){
            return $this->instances[$key];
        }

        $reflectionClass = new ReflectionClass($key);

        $constructor = $reflectionClass->getConstructor();

        $args = $constructor ? $this->getParameters($constructor,$vars) : [];

        $object = $reflectionClass->newInstanceArgs($args);

        $this->instances[$key] = $object;

        return $object;
    }

    /**
     * @param ReflectionMethod $reflect
     * @param array $vars
     * @return array
     * @throws \ReflectionException
     */
    public function getParameters(ReflectionMethod $reflect,$vars=[])
    {
        $args = [];
        if( $reflect->getNumberOfParameters() == 0 )
            return [];

        $parameters = $reflect->getParameters();

        foreach( $parameters as $parameter){
            $name = $parameter->getName();
            //检测此参数是否有默认值
            if(isset($vars[$name])){
                $args[] = $vars[$name];
            }else if($parameter->isDefaultValueAvailable()){
                $args[] = $parameter->getDefaultValue();
            }else{
                throw new \Exception('parameter ' . $name . ' is required');
            }
        }
        return $args;
    }

    /**
     * @param $key 待域名空间的类名或者数组
     * @param string $val 类实例
     */
    public function set($key,$val='')
    {
        if(is_array($key)){
            $this->instances = array_merge($this->instances,$key);
        }else{
            $this->instances[$key] = $val;
        }

        return $this;
    }

    /**
     * @param $key
     * @return bool
     */
    public function exists($key)
    {
        if(isset($this->instances[$key]))
            return true;
        return false;
    }

    /**
     * @param $key
     * @return $this
     */
    public function delete($key)
    {
        unset($this->instances[$key]);
        return $this;
    }
}

测试

note/Person.php

namespace note;

class Person
{
    public $name;
    public $sex;

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

    public function getInfo()
    {
        return $this->name.'想要买辆劳斯莱斯库里南';
    }
}

测试文件

$container       = note\container\Container::getInstance();
$personNamespace = note\Person::class;
$person1         = $container->get($personNamespace,['name'=>'张三','sex'=>25]);
$info            = $person1->getInfo();
//将会输出:张三想要买辆劳斯莱斯库里南
echo $info;
本作品采用《CC 协议》,转载必须注明作者和本文链接
今年不学习,明天惨唧唧。
zs4336
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!