<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>

                ## 中間件 從請求過程中可以看出,第一步就是加載的中間件。那么如何加載的呢?看下面這段代碼 ``` $this->app->middleware ``` 讓 app 實例訪問屬性 middleware?你會發現實例中并沒有這個屬性,那么訪問一個不存在的屬性會發生什么呢?它會去訪問 __get 魔術方法,你有這個想法之后會在 Container 中發現這個魔術方法,最終它會去 make 創建對象,對于 make 的過程請到 `解析 Request` 章節查看。 創建 middleware 的過程中有一個細節,就是加載配置文件 middleware.php,進入到 think\Middleware 文件之后,你會發現這么一段代碼。 ``` public static function __make(App $app, Config $config) { return (new static($config->get('middleware')))->setApp($app); } ``` 正如之前所提到的那樣,使用 make 方法創建對象會執行默認方法 __make,所以這個時候就會將 config 中的 middleware.php 加載進來。目前這個版本似乎沒有加入這個配置文件,你可以手動添加。 來看下面一段代碼,從這段代碼引出中間件的加載過程。 ``` $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php'); ``` 在整個請求過程,首先加載的是 app/middleware.php 文件中的中間件,默認提供了四個中間件。但是這些都是不加載,你可自行選擇打開。然后來看看 import 如何加載的。 ``` public function import(array $middlewares = [], string $type = 'route'): void { foreach ($middlewares as $middleware) { $this->add($middleware, $type); } } ``` `$type` 參數標記了路由的類型,目前只看到 `route` 和 `controller` 兩種類型。默認全局中間件是 `route` 類型的。`add` 方法才是實實在在的導入。來看看的這個方法做了哪些事兒。 ``` public function add($middleware, string $type = 'route'): void { // null 直接返回 if (is_null($middleware)) { return; } // 創建中間件 $middleware = $this->buildMiddleware($middleware, $type); // 加入到中間件隊列,隊列也是分類型的 if ($middleware) { $this->queue[$type][] = $middleware; } } ``` `buildMiddleware` 方法用來創建中間件,做一些解析的工作。來看看代碼的過程,直接在注釋中解釋 ``` protected function buildMiddleware($middleware, string $type = 'route'): array { // 數組類型的 第一個參數必須是中間件,第二個是傳入的參數 if (is_array($middleware)) { list($middleware, $param) = $middleware; } // 如果是 middleware 是閉包, 直接返回 if ($middleware instanceof \Closure) { return [$middleware, $param ?? null]; } // 不支持非字符串的類型 if (!is_string($middleware)) { throw new InvalidArgumentException('The middleware is invalid'); } // 支持鍵值對,正如官方手冊中提到,例如這樣 [ 'hello' => middleware ] if (isset($this->config[$middleware])) { $middleware = $this->config[$middleware]; } // 當你從配置文件解析出來是數組格式,就遞歸調用 if (is_array($middleware)) { $this->import($middleware, $type); return []; } // 最后返回一個 middware 的類名和默認方法 'handle' // handle 方法對中間件而言是必須的,不然無法執行 return [[$middleware, 'handle'], $param ?? null]; } ``` 然后返回會加入到 Queue 隊列中,這個時候你打開全局中間件的其中一個話,隊列中將會是這樣的內容。 ``` array(1) { ["route"]=> array(1) { [0]=> array(2) { [0]=> array(2) { [0]=> string(34) "think\middleware\CheckRequestCache" [1]=> string(6) "handle" } [1]=> NULL } } } ``` 這個和我們預期是一樣的,在代碼解釋過程也沒有遇到任何阻礙。我們繼續往下看,這里僅僅是加入的過程,在后面請求執行的時候來看看如何執行的這些中間件的。 ## 中間件執行 中間件的是由 `Diapatch` 方法執行,而核心在 `resolve` 方法,來看一下這個方法做了什么。 ``` protected function resolve(string $type = 'route') { return function (Request $request) use ($type) { $middleware = array_shift($this->queue[$type]); if (null === $middleware) { throw new InvalidArgumentException('The queue was exhausted, with no response returned'); } // 1 list($call, $param) = $middleware; // 2 if (is_array($call) && is_string($call[0])) { $call = [$this->app->make($call[0]), $call[1]]; } try { // 3 $response = $this->app->invoke($call, [$request, $this->resolve($type), $param]); } catch (HttpResponseException $exception) { $response = $exception->getResponse(); } if (!$response instanceof Response) { throw new LogicException('The middleware must return Response instance'); } return $response; }; } ``` 按照 1,2,3 的步驟進行說明。 隊列使用了 `array_shift` 來進行,說明會執行先進來的中間件。所以你可以在到達控制器之前做很多業務應用初始化的事情。 - 從上面可以知道中間件隊列的數據結構,所以步驟以就是解析出來 middleware 中間件類和參數。 - 如果是數組結構直接解析出對象 - 最重要的就是第三步了,利用反射來執行中間件類,注意在這個執行過程中遞歸調用了,而且記住 `resolve` 返回的始終是閉包,然后在中間件之間傳遞,你可以觀察中間件的 `handle ` 方法的參數,`Request` 對象,第二個閉包,第三個可選參數,正好對上了這個數組參數接口,所以 `handle` 方法的 `$next()` 就是在消費隊列。 所以簡單來說,中間件的過程就是利用隊列在執行消費。保證了中間件的順序執行。
                  <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>

                              哎呀哎呀视频在线观看