Correction status:Uncorrected
Teacher's comments:
在官方文档中对容器(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 . '()'); } }
点击 "运行实例" 按钮查看在线实例
用简单点的来说就是,容器内部是通过反射类或者是闭包函数的方式来实现实例化。
门面实现