多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] ## 第一节: 容器(Container)的功能 > * 容器(Container)的功能,一句话概括就是 **管理对象实例,缓存已创建的实例**。 > 1. 源码分析中可知容器(Conatiner)主要实现为bind()和make()。 > 2. bind()注册内容到容器(Container)的bind或者instances中 > 3. make()获取实例内容,并缓存到容器(Container)的instances中。 > * 核心功能就是**缓存已创建的实例**。 * * * * * ## 第二节:think5中容器(Container)的使用 ### 1 容器(Container)在系统初始化中的注册 ~~~ // 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, // 接口依赖注入 'think\LoggerInterface' => Log::class, ]); ~~~ > 在base.php中注册核心类到容器(Container)的bind。 > 注册完成后,在如下调用时 ~~~ Container::get('app'); ~~~ > 将返回think\app的实例对象。 > 这里的实例对象将缓存到Container的instances中。 > 下次使用上面的调用时 返回缓存的实例对象。 ### 2 容器(Container)在核心类App中的封装 >[info] 在library\think\App.php中。 > 系统的核心应用类App实现为一个具有容器功能的类。 ~~~ // library\think\App.php public function __construct($appPath = '') { $this->container = Container::getInstance(); 。。。。。。 } ~~~ > 创建容器对象保存到App的container属性中。 * * * * * ~~~ // library\think\App.php public function container() { return $this->container; } ~~~ > 获取容器实例 * * * * * ~~~ public function __set($name, $value) { $this->container->bind($name, $value); } public function __get($name) { return $this->container->make($name); } public function __isset($name) { return $this->container->bound($name); } public function __unset($name) { $this->container->__unset($name); } ~~~ > 容器的调用封装 实现容器的快捷操作。 在设置和读取app的属性的时候,如果其属性不存在,则会操作app中的容器。 * * * * * ### 3 容器(Container)在核心类App中的使用 >[info] 类App中封装了容器的功能 > 在设置和获取app的属性时,如果查找的属性不存在,则会对容器进行操作 ~~~ // library\think\App.phhp public function initialize() { // 设置路径环境变量 $this->env->set([ 'think_path' => $this->thinkPath, 'root_path' => $this->rootPath, 'app_path' => $this->appPath, 'config_path' => $this->configPath, 'route_path' => $this->routePath, 'runtime_path' => $this->runtimePath, 'extend_path' => $this->rootPath . 'extend/', 'vendor_path' => $this->rootPath . 'vendor/', ]); // 加载环境变量配置文件 if (is_file($this->rootPath . '.env')) { $this->env->load($this->rootPath . '.env'); } $this->namespace = $this->env->get('app_namespace', $this->namespace); $this->env->set('app_namespace', $this->namespace); // 注册应用命名空间 Loader::addNamespace($this->namespace, $this->appPath); $this->configExt = $this->env->get('config_ext', '.php'); // 初始化应用 $this->init(); // 开启类名后缀 $this->suffix = $this->config('app.class_suffix'); // 应用调试模式 $this->debug = $this->env->get('app_debug', $this->config('app.app_debug')); $this->env->set('app_debug', $this->debug); if (!$this->debug) { ini_set('display_errors', 'Off'); } elseif (PHP_SAPI != 'cli') { //重新申请一块比较大的buffer if (ob_get_level() > 0) { $output = ob_get_clean(); } ob_start(); if (!empty($output)) { echo $output; } } // 注册根命名空间 if (!empty($this->config('app.root_namespace'))) { Loader::addNamespace($this->config('app.root_namespace')); } // 注册类库别名 Loader::addClassAlias($this->config->pull('alias')); // 加载系统助手函数 include $this->thinkPath . 'helper.php'; // 设置系统时区 date_default_timezone_set($this->config('app.default_timezone')); // 监听app_init $this->hook->listen('app_init'); } ~~~ >[danger] 类App中并未声明env,config,hook等属性 > 使用$this->env->xx() $this->config->xx(),$this->hook->xx()就调用了容器功能 > $this->env->xx()获取调App类的__get()方法,进而调用Container->make()方法, > Container->make()方法查找到Container的bind注册的env为Env::class。创建Env对象。 > 调用Env->xx()方法完成$this->evn->xx()的调用 > 其中env与Env::class的关系在上面的所说的base.php进行绑定注册。 > $this->config->xx(),$this->hook->listent()类似 * * * * * ~~~ // library\think\App.php public function run() { // 初始化应用 $this->initialize(); try { if ($this->bind) { // 模块/控制器绑定 $this->route->bind($this->bind); } elseif ($this->config('app.auto_bind_module')) { // 入口自动绑定 $name = pathinfo($this->request->baseFile(), PATHINFO_FILENAME); if ($name && 'index' != $name && is_dir($this->appPath . $name)) { $this->route->bind($name); } } $this->request->filter($this->config('app.default_filter')); // 读取默认语言 $this->lang->range($this->config('app.default_lang')); if ($this->config('app.lang_switch_on')) { // 开启多语言机制 检测当前语言 $this->lang->detect(); } $this->request->langset($this->lang->range()); // 加载系统语言包 $this->lang->load([ $this->thinkPath . 'lang/' . $this->request->langset() . '.php', $this->appPath . 'lang/' . $this->request->langset() . '.php', ]); // 监听app_dispatch $this->hook->listen('app_dispatch'); // 获取应用调度信息 $dispatch = $this->dispatch; if (empty($dispatch)) { // 进行URL路由检测 $dispatch = $this->routeCheck(); } // 记录当前调度信息 $this->request->dispatch($dispatch); // 记录路由和请求信息 if ($this->debug) { $this->log('[ ROUTE ] ' . var_export($this->request->routeinfo(), true)); $this->log('[ HEADER ] ' . var_export($this->request->header(), true)); $this->log('[ PARAM ] ' . var_export($this->request->param(), true)); } // 监听app_begin $this->hook->listen('app_begin'); // 请求缓存检查 $this->request->cache( $this->config('app.request_cache'), $this->config('app.request_cache_expire'), $this->config('app.request_cache_except') ); // 执行调度 $data = $dispatch->run(); } catch (HttpResponseException $exception) { $data = $exception->getResponse(); } // 输出数据到客户端 if ($data instanceof Response) { $response = $data; } elseif (!is_null($data)) { // 默认自动识别响应输出类型 $isAjax = $this->request->isAjax(); $type = $isAjax ? $this->config('app.default_ajax_return') : $this->config('app.default_return_type'); $response = Response::create($data, $type); } else { $response = Response::create(); } // 监听app_end $this->hook->listen('app_end', $response); return $response; } ~~~ > 再举例说明,如上面代码中的 > $this->route->xx(),$this->request->xx(),$this->lang->xx() > 与$this->env->xx()的原理相似 ### 4 容器(Container)在应用中的配置注册 > 为了方便使用容器功能 > think5.1支持在application的模块中通过配置注册自定义的类到容器 ~~~ // library/think/App.php public function init($module = '') { 。。。。。。 // 注册服务和容器对象实例 if (is_file($path . 'provider.php')) { $this->container->bind(include $path . 'provider.php'); } } } ~~~ > 在模块中配置文件provider.php中相关配置 > 将会注册到系统容器中。 > 具体的使用方法见下面的 **容器基本使用章节** * * * * * ### 5 容器(Container)在控制器基类(Controller)的使用 >应用业务的实现主要在继承Controller基类的业务控制器中实现 >控制器基类(Controller)的部分属性使用容器实现 ~~~ // library/think/Controller.php public function __construct() { $this->request = Container::get('request'); $this->app = Container::get('app'); $this->view = Container::get('view')->init( $this->app['config']->pull('template'), $this->app['config']->get('view_replace_str') ); // 控制器初始化 $this->initialize(); // 前置操作方法 if ($this->beforeActionList) { foreach ($this->beforeActionList as $method => $options) { is_numeric($method) ? $this->beforeAction($options) : $this->beforeAction($method, $options); } } } ~~~ > Controller的request,app,view等属性 > 就是通过容器获取的全局唯一Request,App,View对象实例 > 如果在业务控制器的方法中想获取请求信息,系统运行信息, > 就可以直接使用request和app属性。 ~~~ // application\index\controller\Index.php <?php namespace app\index\controller; use think\Controller; class Index extends Controller { public function index() { return '<style type="text/css">*{ padding: 0; margin: 0; } .think_default_text{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p> ThinkPHP V5<br/><span style="font-size:30px">十年磨一剑 - 为API开发设计的高性能框架</span></p><span style="font-size:22px;">[ V5.0 版本由 <a href="http://www.qiniu.com" target="qiniu">七牛云</a> 独家赞助发布 ]</span></div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_bd568ce7058a1091"></thinkad>'; } public function test(){ $request = $this->request; echo '请求参数:'; echo "当前模块名称是" . $request->module(); echo "当前控制器名称是" . $request->controller(); echo "当前操作名称是" . $request->action(); } } ~~~ > 如上$request,直接读取request属性, > 通过Request对象获取当前请求信息 > 同理可以通过app属性获取全局App对象,获取系统的运行信息 ## 第三节: 容器(Container)的总结 1. 容器(Container)主要用来管理对象 2. 容器(Container)的核心功能是缓存已创建对象实例 3. think5.1中的核心应用类App封装了容器的功能 4. think5.1中可以通过操作核心应用类App的属性方法获取相应的对象实例 5. think5.1中控制器基类Controller的app,request,view属性也是使用容器进行管理的 6. 容器(Container)主要用来管理对象。缓存已创建的对象实例。