首页
导航
博客
电子书
算法
众创
代码
随贴
关于我们
您好,欢迎来到码863代码分享网! 请
[登录]
/
[注册]
搜 索
标题:
*
140
字
TAG标签:
(用空格隔开)
30
字
恢复历史版本:
请选择分类
html
python
javascript
php
sql
c
c++
c#
java
plain
所有人可见
仅自己可见
编辑器:UEditor
编辑器:TinyMCE
编辑器:Editor.md
HTML转MD
HTML转MD2
<p>项目目录相对为tp6 <span style="background-color: rgb(215, 227, 188);">4.5执行controller</span></p><p>请求被统一转发到入口文件(入口文件地址为 tp6/index.php)</p><p>1.入口文件引入了composer自动载入文件类库</p><pre class="brush:php;toolbar:false"><php? namespace think; require __DIR__ . '/../vendor/autoload.php';</pre><p><br/></p><p>文件地址为 tp6/vendor/autoload.php')</p><p style="margin: 10px auto; padding: 0px; color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" white-space:="" background-color:=""> </p><p>2.实例化 think\App 对象 赋值给$app</p><pre class="brush:php;toolbar:false"><?php $app = new App();</pre><p><br/></p><p>(App类文件地址为 tp6/vendor/topthink/framework/src/think/App.php')</p><p>执行App类中的__construct构造方法</p><pre class="brush:php;toolbar:false">thinkPath = dirname(__DIR__) . DIRECTORY_SEPARATOR; // 项目根目录 $this->rootPath = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath(); // 应用目录 $this->appPath = $this->rootPath . 'app' . DIRECTORY_SEPARATOR; // 项目缓存目录 $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR; // 加载服务provide容器 if (is_file($this->appPath . 'provider.php')) { // 执行 Container\bind()方法 绑定类、闭包、实例、接口 $this->bind(include $this->appPath . 'provider.php'); } // 设置一个容器实例 static::setInstance($this); // 绑定类的实例到容器 $this->instance('app', $this); $this->instance('think\Container', $this); }</pre><p>中在属性$bind中已经有了一些框架类的别名与实现的映射数组</p><p style="margin: 10px auto; padding: 0px; color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" white-space:="" background-color:=""> </p><p>此时$app因为是继承了Container类,所以$app实际也是一个容器</p><p style="margin: 10px auto; padding: 0px; color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" white-space:="" background-color:=""> </p><p>3.通过$app类调用http类(web管理类)</p><pre class="brush:php;toolbar:false">$http = $app->http;</pre><p><br/></p><p>3.0 引用http类的过程如下:</p><p>(http类文件地址为 tp6/vendor/topthink/framework/src/think/Http.php')</p><p><br/></p><p>3.1 首先App中不存在http方法,但是在容器类中存在魔术方法__get,会触发该魔术方法</p><pre class="brush:php;toolbar:false">get($name); }</pre><p><span style="color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" background-color:="">get方法从app应用容器中获取http对象实例</span></p><pre class="brush:php;toolbar:false">has($abstract)) { return $this->make($abstract); } throw new ClassNotFoundException('class not exists: ' . $abstract, $abstract); }</pre><p><span style="color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" background-color:=""><br/></span></p><p><span style="color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" background-color:="">3.2 通过app应用容器中的make方法进行类的实例,以及执行instances方法将实例化的http类绑定到容器数组对象中</span></p><p><span style="color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" background-color:=""><br/></span></p><pre class="brush:php;toolbar:false">getAlias($abstract); if (isset($this->instances[$abstract]) && !$newInstance) { return $this->instances[$abstract]; } if (isset($this->bind[$abstract]) && $this->bind[$abstract] instanceof Closure) { $object = $this->invokeFunction($this->bind[$abstract], $vars); } else { $object = $this->invokeClass($abstract, $vars); } if (!$newInstance) { $this->instances[$abstract] = $object; } return $object; }</pre><p><br/></p><p>返回http对象实例到调用处 第3步开始的地方</p><p style="margin: 10px auto; padding: 0px; color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" white-space:="" background-color:=""> </p><p>4 http对象执行run方法,应用程序的执行开始</p><pre class="brush:php;toolbar:false">app->make('request', [], true); // 绑定request类的实例化对象到容器中 $this->app->instance('request', $request); try { // 执行应用程序返回response类 $response = $this->runWithRequest($request); } catch (Throwable $e) { $this->reportException($e); $response = $this->renderException($request, $e); } return $response; }</pre><p><br/></p><p>4.1 run 方法中首先创建Request类,执行instances方法将实例化的Request类绑定到容器数组对象中,标识为request</p><p style="margin: 10px auto; padding: 0px; color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" white-space:="" background-color:=""> </p><p>然后进行路由调度,执行 app容器中runWithRequest方法</p><pre class="brush:php;toolbar:false">/** * 执行应用程序 * @param Request $request * @return mixed */ protected function runWithRequest(Request $request) { // 初始化app应用程序 $this->initialize(); // 加载全局中间件 $this->loadMiddleware(); // 监听HttpRun $this->app->event->trigger(HttpRun::class); // 中间件调度 return $this->app->middleware->pipeline() ->send($request) ->then(function ($request) { return $this->dispatchToRoute($request); }); }</pre><p><br/></p><p>4.2然后在在http类中runWithRequest方法中执行了dispatchToRoute 讲请求分发到路由</p><p> (dispatchToRoute 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/Route.php')</p><p>// 分发请求到路由</p><pre class="brush:php;toolbar:false">app->config->get('app.with_route', true) ? function () { $this->loadRoutes(); } : null; // 执行路由调度 return $this->app->route->dispatch($request, $withRoute); }</pre><p><span style="color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" background-color:=""><br/></span></p><p><span style="color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" background-color:="">4.3 在http类中dispatchToRoute 通过app容器获取了route实例,并调用了route实例中的dispatch方法</span></p><p><span style="color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" background-color:=""><br/></span></p><pre class="brush:php;toolbar:false">request = $request; $this->host = $this->request->host(true); $this->init(); if ($withRoute) { // 加载路由设置 if ($withRoute instanceof Closure) { $withRoute(); } // 检查路由 $dispatch = $this->check(); } else { // 如果没有路由,则使用默认url解析 $dispatch = $this->url($this->path()); } // $dispatch 为think\route\dispatch\Controller 的实例化 中的初始化,提取控制名称以及操作名称 // 1, 通过最终think\route\Rule::dispatch来确路由调度的最终执行动作 $dispatch->init($this->app); return $this->app->middleware->pipeline('route') ->send($request) ->then(function () use ($dispatch) { // 执行动作方法 return $dispatch->run(); }); }</pre><p><br/></p><p>4.4 在route类中的dispatch中执行了run方法, </p><p>(run 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/route/Dispatch.php')</p><pre class="brush:php;toolbar:false"><?php /** * 执行路由调度 * @access public * @return mixed */ public function run(): Response { if ($this->rule instanceof RuleItem && $this->request->method() == 'OPTIONS' && $this->rule->isAutoOptions()) { $rules = $this->rule->getRouter()->getRule($this->rule->getRule()); $allow = []; foreach ($rules as $item) { $allow[] = strtoupper($item->getMethod()); } return Response::create('', 'html', 204)->header(['Allow' => implode(', ', $allow)]); } // 此处调用的$this类,由调用者确定, 可能为url, callback, 或者controller // $data 为返回的response 类 $data = $this->exec(); return $this->autoResponse($data); }</pre><p><br/></p><p><br/></p><p>4.5 run方法调用了exec <span style="background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);">这里重要 执行了controller $this->app->invokeReflectMethod($instance, $reflect, $vars);</span></p><p>(此处调用的exec的类方法所在的文件,由调用者确定, 可能为url, callback, 或者controller, exec 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/route/dispatch/Callback.php|Controller.php')</p><p>在exec方法中最终返回了data数据 </p><pre class="brush:php;toolbar:false"> public function exec() { try { // 实例化控制器 $instance = $this->controller($this->controller); } catch (ClassNotFoundException $e) { throw new HttpException(404, 'controller not exists:' . $e->getClass()); } // 注册控制器中间件 $this->registerControllerMiddleware($instance); return $this->app->middleware->pipeline('controller') ->send($this->request) ->then(function () use ($instance) { // 获取当前操作名 $suffix = $this->rule->config('action_suffix'); $action = $this->actionName . $suffix; if (is_callable([$instance, $action])) { $vars = $this->request->param(); try { $reflect = new ReflectionMethod($instance, $action); // 严格获取当前操作方法名 $actionName = $reflect->getName(); if ($suffix) { $actionName = substr($actionName, 0, -strlen($suffix)); } $this->request->setAction($actionName); } catch (ReflectionException $e) { $reflect = new ReflectionMethod($instance, '__call'); $vars = [$action, $vars]; $this->request->setAction($action); } } else { // 操作不存在 throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()'); } $data = $this->app->invokeReflectMethod($instance, $reflect, $vars); return $this->autoResponse($data); }); }</pre><p style="margin: 10px auto; padding: 0px; color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" white-space:="" background-color:=""> <br/></p><p>4.6 然后调用了autoResponse方法,并传递4.5返回的data数据</p><p>(autoResponse 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/route/Dispatch.php')</p><pre class="brush:php;toolbar:false">request->isJson() ? 'json' : 'html'; $response = Response::create($data, $type); } else { $data = ob_get_clean(); $content = false === $data ? '' : $data; $status = '' === $content && $this->request->isJson() ? 204 : 200; // 创建response类返回,使用html $response = Response::create($content, 'html', $status); } return $response; }</pre><p style="margin: 10px auto; padding: 0px;"> </p><p>4.7 autoResponse 方法中执行了 Response::create方法</p><p>最终方法返回了response对象;</p><p>(Response::create 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/Response.php')</p><pre class="brush:php;toolbar:false">invokeClass($class, [$data, $code]); }</pre><p style="margin: 10px auto; padding: 0px;"> </p><p>4.8 最终返回了 response Html类的对象实例</p><p style="margin: 10px auto; padding: 0px; color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" white-space:="" background-color:=""> </p><p>5 执行run方法</p><pre class="brush:php;toolbar:false">$response = $http->run();</pre><p style="margin: 10px auto; padding: 0px; color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" white-space:="" background-color:=""> </p><p>6 response 执行send输出数据的操作;</p><p>(Html 类文件所在地址为 tp6/vendor/topthink/framework/src/think/response/Html.php )</p><p style="margin: 10px auto; padding: 0px; color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" white-space:="" background-color:=""> </p><p>6.1 执行send方法</p><p>(send方法 类文件所在地址为 tp6/vendor/topthink/framework/src/think/Response.php )</p><p>$response->send();</p><pre class="brush:php;toolbar:false">getContent(); if (!headers_sent() && !empty($this->header)) { // 发送状态码 http_response_code($this->code); // 发送头部信息 foreach ($this->header as $name => $val) { header($name . (!is_null($val) ? ':' . $val : '')); } } if ($this->cookie) { $this->cookie->save(); } $this->sendData($data); if (function_exists('fastcgi_finish_request')) { // 提高页面响应 fastcgi_finish_request(); } }</pre><p style="margin: 10px auto; padding: 0px;"> </p><p style="margin: 10px auto; padding: 0px; color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" white-space:="" background-color:=""> </p><p>6.1 在send方法中最终执行了 sendData 方法</p><p>(sendData方法 类文件所在地址为 tp6/vendor/topthink/framework/src/think/Response.php )</p><pre class="brush:php;toolbar:false"><?php /** * 输出数据 * @access protected * @param string $data 要处理的数据 * @return void */ protected function sendData(string $data): void { echo $data; }</pre><p style="margin: 10px auto; padding: 0px;"> </p><p>7 执行 http对象中的end方法</p><pre class="brush:php;toolbar:false">end($response);</pre><p><span style="color: rgb(51, 51, 51); font-family: " pingfang="" microsoft="" helvetica="" font-size:="" background-color:="">(http类文件地址为 tp6/vendor/topthink/framework/src/think/Http.php')</span></p><pre class="brush:php;toolbar:false"><?php /** * HttpEnd * @param Response $response * @return void */ public function end(Response $response): void { $this->app->event->trigger(HttpEnd::class, $response); //执行中间件 $this->app->middleware->end($response); // 写入日志 $this->app->log->save(); }</pre><p style="margin: 10px auto; padding: 0px;"> </p><p>8整个程序结束</p><p> </p><p>应用类App继承了Container容器类, 所有类的实例通过容器类进行统一管理,容器类为单例模式全局唯一;</p><p><br/></p>
CopyRight 2002~2023 精通2100网 联系邮箱:qqtxt@163.com
版权所有:精通2100网
湘ICP备2023018646号-1
MYSQl共执行 4 个查询,用时 0.0020127296447754 秒,PHP脚本用时 0.004920 秒,占用内存 0.695 MB,Gzip 已启用