Blogger Information
Blog 64
fans 2
comment 3
visits 75755
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
Thinkphp5.1 容器于门面的认识—2018年5月29日08:51:45
清雨的博客
Original
1402 people have browsed it

在官方文档中对容器(Container):用来更方便的管理类依赖及运行依赖注入。

门面(Facade):门面为容器中的类提供了一个静态调用接口,相比于传统的静态方法调用, 带来了更好的可测试性和扩展性,你可以为任何的非静态类库定义一个facade类。


容器主要是由think\Container 类完成,单大多数情况是由助手函数完成操作。

看源代码的实现方式

实例

// 注册核心类的静态代理
Facade::bind([
    facade\App::class        => App::class,
    facade\Build::class      => Build::class,
    facade\Cache::class      => Cache::class,
    facade\Config::class     => Config::class,
    facade\Cookie::class     => Cookie::class,
    facade\Debug::class      => Debug::class,
    facade\Env::class        => Env::class,
    facade\Hook::class       => Hook::class,
    facade\Lang::class       => Lang::class,
    facade\Log::class        => Log::class,
    facade\Middleware::class => Middleware::class,
    facade\Request::class    => Request::class,
    facade\Response::class   => Response::class,
    facade\Route::class      => Route::class,
    facade\Session::class    => Session::class,
    facade\Url::class        => Url::class,
    facade\Validate::class   => Validate::class,
    facade\View::class       => View::class,
]);

// 注册类库别名
Loader::addClassAlias([
    'App'      => facade\App::class,
    'Build'    => facade\Build::class,
    'Cache'    => facade\Cache::class,
    'Config'   => facade\Config::class,
    'Cookie'   => facade\Cookie::class,
    'Db'       => Db::class,
    'Debug'    => facade\Debug::class,
    'Env'      => facade\Env::class,
    'Facade'   => Facade::class,
    'Hook'     => facade\Hook::class,
    'Lang'     => facade\Lang::class,
    'Log'      => facade\Log::class,
    'Request'  => facade\Request::class,
    'Response' => facade\Response::class,
    'Route'    => facade\Route::class,
    'Session'  => facade\Session::class,
    'Url'      => facade\Url::class,
    'Validate' => facade\Validate::class,
    'View'     => facade\View::class,
]);

运行实例 »

点击 "运行实例" 按钮查看在线实例

容器的实现方式:

在这里容器已经绑定了系统常用的类到了容器中,在使用时只需要调用助手函数app()进行容器猴子那个的类解析调用方可,对于已经绑定的的类,会自动进行实例化。

实例

//查看源码,Container调用的其实是make方法,在该方法里调用反射等实现类的实例化,过程如下:
 /**
     * 创建类的实例
     * @access public
     * @param  string        $abstract       类名或者标识
     * @param  array|true    $vars           变量
     * @param  bool          $newInstance    是否每次创建新的实例
     * @return object
     */
    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])) {
            $concrete = $this->bind[$abstract];
             //闭包实现
            if ($concrete instanceof Closure) {
                $object = $this->invokeFunction($concrete, $vars);
            } else {
                $this->name[$abstract] = $concrete;
                return $this->make($concrete, $vars, $newInstance);
            }
        } else {
           //反射实现
            $object = $this->invokeClass($abstract, $vars);
        }

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

        return $object;
    }



 /**
     * 调用反射执行类的实例化 支持依赖注入
     * @access public
     * @param  string    $class 类名
     * @param  array     $vars  参数
     * @return mixed
     */
    public function invokeClass($class, $vars = [])
    {
        try {
            $reflect = new ReflectionClass($class);

            if ($reflect->hasMethod('__make')) {
                $method = new ReflectionMethod($class, '__make');

                if ($method->isPublic() && $method->isStatic()) {
                    $args = $this->bindParams($method, $vars);
                    return $method->invokeArgs(null, $args);
                }
            }

            $constructor = $reflect->getConstructor();

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

            return $reflect->newInstanceArgs($args);

        } catch (ReflectionException $e) {
            throw new ClassNotFoundException('class not exists: ' . $class, $class);
        }
    }





    /**
     * 执行函数或者闭包方法 支持参数调用
     * @access public
     * @param  mixed  $function 函数或者闭包
     * @param  array  $vars     参数
     * @return mixed
     */
    public function invokeFunction($function, $vars = [])
    {
        try {
            $reflect = new ReflectionFunction($function);

            $args = $this->bindParams($reflect, $vars);

            return call_user_func_array($function, $args);
        } catch (ReflectionException $e) {
            throw new Exception('function not exists: ' . $function . '()');
        }
    }

运行实例 »

点击 "运行实例" 按钮查看在线实例

用简单点的来说就是,容器内部是通过反射类或者是闭包函数的方式来实现实例化。

门面实现


Correction status:Uncorrected

Teacher's comments:
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
1 comments
天蓬老师 2018-05-30 09:22:53
仅将官方文档中的内容简单的复制粘贴,而无自己的独立见解,难以领会外观模式Facade的精华~~ 二点建议: 1. 不要抄官方源码,自己写源码进行描述; 2. 加上自己对该设计模式的理解,哪怕是有偏差的也没关系; 希望你重新完成本次作业~~
1 floor
Author's latest blog post