<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] # 說明 接上一篇繼續分析。控制器操作的代碼實際上都包含在`$this->dispatchToRoute($request)`中,展開來看: ``` protected function dispatchToRoute($request) { $withRoute = $this->app->config->get('app.with_route', true) ? function () { $this->loadRoutes(); } : null; return $this->app->route->dispatch($request, $withRoute); } ``` 上一節我們跳過路由,分析了URL解析,下面接著分析控制器和操作的解析。 `dispatch`方法: ``` public function dispatch(Request $request, $withRoute = null) { $this->request = $request; $this->host = $this->request->host(true); $this->init(); if ($withRoute) { //加載路由 $withRoute(); $dispatch = $this->check(); } else { $dispatch = $this->url($this->path()); } $dispatch->init($this->app); return $this->app->middleware->pipeline('route') ->send($request) ->then(function () use ($dispatch) { return $dispatch->run(); }); } ``` 重點關注后面的`return`語句,這里又給控制器操作的代碼包裹上了中間件閉包,其原理也跟前面分析的全局中間件原理一樣,不再贅述。重點的重點關注`run`方法。 # 控制器類的 run 方法分析 `run`方法代碼如下: ``` public function run(): Response { // HTTP的OPTIONS方法用于獲取目的資源所支持的通信選項。 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('', '', 204)->header(['Allow' => implode(', ', $allow)]); } //這里的exec方法位于Controller類 $data = $this->exec(); // 控制器操作返回的數據,進一步加工,設置Http報頭、狀態碼等,返回一個Response對象 return $this->autoResponse($data); } ``` 分析詳見注釋。主要的邏輯在`$data = $this->exec()`,其中,注意`exec`方法位于`think\route\dispatch\Controller`類,其代碼如下: ``` public function exec() { try { // 實例化控制器 $instance = $this->controller($this->controller); } catch (ClassNotFoundException $e) { throw new HttpException(404, 'controller not exists:' . $e->getClass()); } //A 注冊控制器中間件 $this->registerControllerMiddleware($instance); // 這里跟前面全局中間件原理一樣,不再分析 return $this->app->middleware->pipeline('controller') ->send($this->request) ->then(function () use ($instance) { // 獲取當前操作名 $action = $this->actionName . $this->rule->config('action_suffix'); if (is_callable([$instance, $action])) { $vars = $this->request->param(); try { $reflect = new ReflectionMethod($instance, $action); // 嚴格獲取當前操作方法名 $actionName = $reflect->getName(); $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); }); } ``` 詳細分析見代碼注釋,以下再展開分析控制器的實例化和控制器中間件的注冊。 ## A 控制器的實例化 執行實例化的`think\route\dispatch\Controller`類的`controller`方法代碼如下: ``` public function controller(string $name) { // 是否使用控制器后綴 $suffix = $this->rule->config('controller_suffix') ? 'Controller' : ''; // 訪問控制器層名稱 $controllerLayer = $this->rule->config('controller_layer') ?: 'controller'; // 空控制器名稱 $emptyController = $this->rule->config('empty_controller') ?: 'Error'; //獲取控制器完整的類名 $class = $this->app->parseClass($controllerLayer, $name . $suffix); // 如果這個類存在 if (class_exists($class)) { //通過容器獲取實例(非單例模式) return $this->app->make($class, [], true); //不存在時,如果有空控制器的類存在 } elseif ($emptyController && class_exists($emptyClass = $this->app->parseClass($controllerLayer, $emptyController . $suffix))) { //同理,實例化空控制器 return $this->app->make($emptyClass, [], true); } // 如果找不到控制器的類,且連控控制器也沒有,拋出錯誤 throw new ClassNotFoundException('class not exists:' . $class, $class); } ``` 具體分析見注釋。 ## B 控制器中間件注冊 執行注冊的`registerControllerMiddleware`方法代碼如下: ``` protected function registerControllerMiddleware($controller): void { // 獲取反射類對象 $class = new ReflectionClass($controller); // 檢查控制器類是否有middleware屬性 if ($class->hasProperty('middleware')) { //提取middleware變量 $reflectionProperty = $class->getProperty('middleware'); //設置可見性為公有 $reflectionProperty->setAccessible(true); //獲取middleware屬性的值 $middlewares = $reflectionProperty->getValue($controller); //解析控制器中間件配置 foreach ($middlewares as $key => $val) { if (!is_int($key)) { //如果有設置only屬性 //$this->request->action(true)獲取當前操作名并轉為小寫 //$val['only']各元素也轉為小寫,然后判斷當前操作是否在$val['only']里面 //不在則跳過(說明該操作不需要執行該中間件) if (isset($val['only']) && !in_array($this->request->action(true), array_map(function ($item) { return strtolower($item); }, is_string($val['only']) ? explode(",", $val['only']) : $val['only']))) { continue; //如果有設置except屬性,且當前操作在$val['except']里面,說明當前操作不需要該中間件,跳過 } elseif (isset($val['except']) && in_array($this->request->action(true), array_map(function ($item) { return strtolower($item); }, is_string($val['except']) ? explode(',', $val['except']) : $val['except']))) { continue; } else { //保存中間件名稱或者類 $val = $key; } } if (is_string($val) && strpos($val, ':')) {\ $val = explode(':', $val, 2);\ } //注冊控制器中間件,跟前面注冊路由中間件一樣原理,只是,中間件的type為controller $this->app->middleware->controller($val); } } } ``` 分析詳見注釋。 # 總結 長路漫漫,到這里,終于分析完了`runWithRequest`方法,前面的分析,基本是圍繞著`runWithRequest`方法展開。現在,讓我們將目光轉回Http類的`run`方法: ``` public function run(Request $request = null): Response { . . . try { $response = $this->runWithRequest($request); } catch (Throwable $e) { $this->reportException($e); $response = $this->renderException($request, $e); } // 設置cookie并返回響應對象 return $response; } ``` `runWithRequest`方法跑完,`run`方法也差不多結束了,最終它返回一個`Response`對象。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看