🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
项目目录相对为tp6 请求被统一转发到入口文件(入口文件地址为 tp6/index.php) 1.入口文件引入了composer自动载入文件类库 ``` `<php?` `namespace``think;` `require``__DIR__ .``'/../vendor/autoload.php'``;` ``` (文件地址为 tp6/vendor/autoload.php') 2.实例化 think\\App 对象 赋值给$app ``` `<?php` `$app``=``new``App();` ``` (App类文件地址为 tp6/vendor/topthink/framework/src/think/App.php') 执行App类中的\_\_construct构造方法 ``` `<?php` `public``function``__construct(string``$rootPath``=``''``)` `{` `// 框架类库目录` `$this``->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``);` `}` ``` 其中在属性$bind中已经有了一些框架类的别名与实现的映射数组 此时$app因为是继承了Container类,所以$app实际也是一个容器 3.通过$app类调用http类(web管理类) ``` `$http``=``$app``->http;` ``` 3.0 引用http类的过程如下: (http类文件地址为 tp6/vendor/topthink/framework/src/think/Http.php') 3.1 首先App中不存在http方法,但是在容器类中存在魔术方法\_\_get,会触发该魔术方法 ``` `<?php` `public``function``__get(``$name``)` `{` `return``$this``->get(``$name``);` `}` ``` get方法从app应用容器中获取http对象实例 ``` `<php?` `/**` `* 获取容器中的对象实例` `* @access public` `* @param string $abstract 类名或者标识` `* @return object` `*/` `public``function``get(``$abstract``)` `{` `if``(``$this``->has(``$abstract``)) {` `return``$this``->make(``$abstract``);` `}` `throw``new``ClassNotFoundException(``'class not exists: '``.``$abstract``,``$abstract``);` `}` ``` 3.2 通过app应用容器中的make方法进行类的实例,以及执行instances方法将实例化的http类绑定到容器数组对象中 ``` `<?php` `/**` `* 创建类的实例 已经存在则直接获取` `* @access public` `* @param string $abstract    类名或者标识` `* @param array  $vars        变量` `* @param bool   $newInstance 是否每次创建新的实例` `* @return mixed` `*/` `public``function``make(string``$abstract``,``array``$vars``= [], bool``$newInstance``= false)` `{` `$abstract``=``$this``->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``;` `}` ``` 返回http对象实例到调用处 第3步开始的地方 4 http对象执行run方法,应用程序的执行开始 ``` `<?php` `/**` `* 执行应用程序` `* @access public` `* @param Request|null $request` `* @return Response` `*/` `public``function``run(Request``$request``= null): Response` `{` `//自动创建request对象` `$request``=``$request``??``$this``->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``;` `}` ``` 4.1 run 方法中首先创建Request类,执行instances方法将实例化的Request类绑定到容器数组对象中,标识为request 然后进行路由调度,执行 app容器中runWithRequest方法 ``` `/**` `* 执行应用程序` `* @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``);` `});` `}` ``` 4.2然后在在http类中runWithRequest方法中执行了dispatchToRoute 讲请求分发到路由  (dispatchToRoute 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/Route.php') // 分发请求到路由 ``` `<?php` `protected``function``dispatchToRoute(``$request``)` `{` `// 是否启用路由, 默认启用路由` `$withRoute``=``$this``->app->config->get(``'app.with_route'``, true) ?``function``() {` `$this``->loadRoutes();` `} : null;` `// 执行路由调度` `return``$this``->app->route->dispatch(``$request``,``$withRoute``);` `}` ``` 4.3 在http类中dispatchToRoute 通过app容器获取了route实例,并调用了route实例中的dispatch方法 ``` <?php /\*\* \* 路由调度 \* @param Request $request \* @param Closure|bool $withRoute \* @return Response \*/ public function dispatch(Request $request, $withRoute = true) {     $this->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();         }); } ``` 4.4 在route类中的dispatch中执行了run方法,  (run 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/route/Dispatch.php') ``` `<?php<br>``/**` `* 执行路由调度` `* @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``);` `}` ``` 4.5 run方法调用了exec  (此处调用的exec的类方法所在的文件,由调用者确定, 可能为url, callback, 或者controller, exec 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/route/dispatch/Callback.php|Controller.php') 在exec方法中最终返回了data数据 4.6 然后调用了autoResponse方法,并传递4.5返回的data数据 (autoResponse 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/route/Dispatch.php') ``` `<?php` `protected``function``autoResponse(``$data``): Response` `{` `if``(``$data``instanceof``Response) {` `$response``=``$data``;` `}``elseif``(!``is_null``(``$data``)) {` `// 默认自动识别响应输出类型` `$type`    `=``$this``->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``;` `}` ``` 4.7 autoResponse 方法中执行了 Response::create方法 最终方法返回了response对象; (Response::create 类方法的文件地址为 tp6/vendor/topthink/framework/src/think/Response.php') ``` `<?php` `/**` `* 创建Response对象` `* @access public` `* @param  mixed  $data 输出数据` `* @param  string $type 输出类型` `* @param  int    $code 状态码` `* @return Response` `*/` `public``static``function``create(``$data``=``''``, string``$type``=``'html'``, int``$code``= 200): Response` `{` `$class``= false !==``strpos``(``$type``,``'\\'``) ?``$type``:``'\\think\\response\\'``. ucfirst(``strtolower``(``$type``));` `return``Container::getInstance()->invokeClass(``$class``, [``$data``,``$code``]);` `}` ``` 4.8 最终返回了 response Html类的对象实例 5 执行run方法 ``` `$response``=``$http``->run();` ``` 6 response 执行send输出数据的操作; (Html 类文件所在地址为 tp6/vendor/topthink/framework/src/think/response/Html.php ) 6.1 执行send方法 (send方法 类文件所在地址为 tp6/vendor/topthink/framework/src/think/Response.php ) $response->send(); ``` `<?php` `/**` `* 发送数据到客户端` `* @access public` `* @return void` `* @throws \InvalidArgumentException` `*/` `public``function``send(): void` `{` `// 处理输出数据` `$data``=``$this``->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();` `}` `}` ``` 6.1 在send方法中最终执行了 sendData 方法 (sendData方法 类文件所在地址为 tp6/vendor/topthink/framework/src/think/Response.php ) ``` `<?php` `/**` `* 输出数据` `* @access protected` `* @param string $data 要处理的数据` `* @return void` `*/` `protected``function``sendData(string``$data``): void` `{` `echo``$data``;` `}` ``` 7 执行 http对象中的end方法 ``` `<?php` `$http``->``end``(``$response``);` ``` (http类文件地址为 tp6/vendor/topthink/framework/src/think/Http.php') ``` `<?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();` `}` ``` 8整个程序结束 应用类App继承了Container容器类, 所有类的实例通过容器类进行统一管理,容器类为单例模式全局唯一; ![](https://img.kancloud.cn/12/6e/126ee53d8e0378f737432c5c93a17b62_1511x1600.jpg)