TP5.1的核心代码解析之容器

最近看了看ThinkPHP5.1的核心代码,使用了容器的思想,简单解析一下具体实现:

首先看到

\thinkphp\base.php

文件中的初始化绑定类到容器的方法:

// 注册核心类到容器
Container::getInstance()->bind([
    'app'                   => App::class,
    'build'                 => Build::class,
    'cache'                 => Cache::class,
    'config'                => Config::class,
    'cookie'                => Cookie::class,
    'debug'                 => Debug::class,
    'env'                   => Env::class,
    'hook'                  => Hook::class,
    'lang'                  => Lang::class,
    'log'                   => Log::class,
    'request'               => Request::class,
    'response'              => Response::class,
    'route'                 => Route::class,
    'session'               => Session::class,
    'url'                   => Url::class,
    'validate'              => Validate::class,
    'view'                  => View::class,
    'middlewareDispatcher'  => http\middleware\Dispatcher::class,
    // 接口依赖注入
    'think\LoggerInterface' => Log::class,
]);

Container类就是所说的容器类,绑定的本质其实就是绑定了类的简称和类的真实名称(方便后面用简称实例化类):

/**
     * 绑定一个类、闭包、实例、接口实现到容器
     * @access public
     * @param  string|array  $abstract    类标识、接口
     * @param  mixed         $concrete    要绑定的类、闭包或者实例
     * @return $this
     */
    public function bind($abstract, $concrete = null)
    {
        if (is_array($abstract)) {
            $this->bind = array_merge($this->bind, $abstract);
        } elseif ($concrete instanceof Closure) {
            $this->bind[$abstract] = $concrete;
        } elseif (is_object($concrete)) {
            $this->instances[$abstract] = $concrete;
        } else {
            $this->bind[$abstract] = $concrete;
        }
        return $this;
    }

可以看到如上面的代码(这里先不考虑闭包也就是Closure)的情况,可以看到其实就是将这个绑定的数组传到类中的$this->bind参数中,方便使用,具体使用方式如下:

$app    = Container::get('app');

如上面的代码实际上调用了Container类中的下面方法:

/**
     * 获取容器中的对象实例
     * @access public
     * @param  string        $abstract       类名或者标识
     * @param  array|true    $vars           变量
     * @param  bool          $newInstance    是否每次创建新的实例
     * @return object
     */
    public static function get($abstract, $vars = [], $newInstance = false)
    {
        return static::getInstance()->make($abstract, $vars, $newInstance);
    }

也就是make方法:

/**
     * 创建类的实例
     * @access public
     * @param  string        $abstract       类名或者标识
     * @param  array|true    $args           变量
     * @param  bool          $newInstance    是否每次创建新的实例
     * @return object
     */
    public function make($abstract, $vars = [], $newInstance = false)
    {
        if (true === $vars) {
            // 总是创建新的实例化对象
            $newInstance = true;
            $vars        = [];
        }
        if (isset($this->instances[$abstract]) && !$newInstance) {
            $object = $this->instances[$abstract];
        } else {
            if (isset($this->bind[$abstract])) {
                $concrete = $this->bind[$abstract];
                if ($concrete instanceof Closure) {
                    $object = $this->invokeFunction($concrete, $vars);
                } else {
                    $object = $this->make($concrete, $vars, $newInstance);
                }
            } else {
                $object = $this->invokeClass($abstract, $vars);
            }

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

其他可以忽略,其实质就是:

如果$newInstance不为true,
直接就会调用$object = $this->invokeClass($abstract, $vars);方法来实例化类,
而$abstract的名称本质就是用$this->bind的上面绑定的数组获取的类(这里是app)
的真实命名(上面传的App::class)

当然中间可能绕了一下,实际上就是这样。

invokeClass方法如下:

/**
     * 调用反射执行类的实例化 支持依赖注入
     * @access public
     * @param  string    $class 类名
     * @param  array     $vars  变量
     * @return mixed
     */
    public function invokeClass($class, $vars = [])
    {
        $reflect     = new ReflectionClass($class);
        $constructor = $reflect->getConstructor();
        if ($constructor) {
            $args = $this->bindParams($constructor, $vars);
        } else {
            $args = [];
        }
        return $reflect->newInstanceArgs($args);
    }

至于容器,我的理解就是借助一个第三方类统一管理并获取你需要的类的实例。

以上

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值