laravel的生命週期
世間萬物皆有生命週期,當我們使用任何工具時都需要理解它的工作原理,那麼用起來就會得心應手,應用開發也是如此。理解了它的原理,那麼使用起來就會遊刃有餘。
在瞭解 Laravel 的生命週期前,我們先回顧一下PHP 的生命週期。
PHP 的生命週期
PHP 的執行模式
PHP兩種執行模式是WEB模式、CLI模式。
- 當我們在終端敲入php這個命令的時候,使用的是CLI模式。
- 當使用Nginx或者別web伺服器作為宿主處理一個到來的請求時,使用的是WEB模式。
生命週期
當我們請求一個php
檔案時,PHP 為了完成這次請求,會發生5個階段的生命週期切換:
-
模組初始化(MINIT),即呼叫
php.ini
mysql
擴充套件。 -
請求初始化(RINIT),即初始化為執行本次指令碼所需要的變數名稱和變數值內容的符號表,如
$_SESSION
變數。 -
執行該PHP指令碼。
-
請求處理完成(Request Shutdown),按順序呼叫各個模組的
RSHUTDOWN
方法,對每個變數呼叫unset
函式,如unset $_SESSION
變數。 -
關閉模組(Module Shutdown) , PHP呼叫每個擴充套件的
MSHUTDOWN
方法,這是各個模組最後一次釋放記憶體的機會。這意味著沒有下一個請求了。
WEB模式和CLI(命令列)模式很相似,區別是:
- CLI 模式會在每次指令碼執行經歷完整的5個週期,因為你指令碼執行完不會有下一個請求;
- WEB模式為了應對併發,可能採用多執行緒,因此生命週期
1
和5
有可能只執行一次,下次請求到來時重複2-4
的生命週期,這樣就節省了系統模組初始化所帶來的開銷。
可以看出PHP生命週期是很對稱的。說了這麼多,就是為了定位Laravel執行在哪裡,沒錯,Laravel僅僅執行再 第三個階段:
PHP生命週期作用
理解這些,你就可以優化你的 Laravel
程式碼,可以更加深入的瞭解 Laravel 的singleton
(單例)。至少你知道了,每一次請求結束,PHP 的變數都會 unset
,Laravel 的 singleton
singleton
;你在 Laravel 中的靜態變數也不能在多個請求之間共享,因為每一次請求結束都會 unset
。理解這些概念,是寫高質量程式碼的第一步,也是最關鍵的一步。因此記住,PHP是一種指令碼語言,所有的變數只會在這一次請求中生效,下次請求之時已被重置,而不像Java靜態變數擁有全域性作用。
Laravel 的生命週期
概述
Laravel 的生命週期從public\index.php
開始,從public\index.php
結束。
下面是 public\index.php
的全部原始碼,更具體來說可以分為四步:
1. require __DIR__.'/../bootstrap/autoload.php';
2. $app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
3. $response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response->send();
4. $kernel->terminate($request,$response);
複製程式碼
以下是四步詳細的解釋是:
composer自動載入需要的類
- 檔案載入composer生成的自動載入設定,包括所有你
composer require
的依賴。 - 生成容器Container,Application例項,並向容器註冊核心元件(HttpKernel,ConsoleKernel ,ExceptionHandler)(對應程式碼2,容器很重要,後面詳細講解)。
- 處理請求,生成併傳送響應(對應程式碼3,毫不誇張的說,你99%的程式碼都執行在這個小小的handle 方法裡面)。
- 請求結束,進行回撥(對應程式碼4,還記得可終止中介軟體嗎?沒錯,就是在這裡回撥的)。
我們不妨在詳細一點:
第一步:註冊載入composer自動生成的class loader
就是載入初始化第三方依賴。
第二步:生成容器 Container
並向容器註冊核心元件,是從 bootstrap/app.php
指令碼獲取 Laravel 應用例項,
第三步:這一步是重點,處理請求,並生成傳送響應。
請求被髮送到 HTTP
核心或 Console
核心,這取決於進入應用的請求型別。
取決於是通過瀏覽器請求還是通過控制檯請求。這裡我們主要是通過瀏覽器請求。
HTTP 核心繼承自 Illuminate\Foundation\Http\Kernel 類,該類定義了一個 bootstrappers 陣列,這個陣列中的類在請求被執行前執行,這些 bootstrappers 配置了錯誤處理、日誌、檢測應用環境以及其它在請求被處理前需要執行的任務。
protected $bootstrappers = [
//註冊系統環境配置 (.env)
'Illuminate\Foundation\Bootstrap\DetectEnvironment',//註冊系統配置(config)
'Illuminate\Foundation\Bootstrap\LoadConfiguration',//註冊日誌配置
'Illuminate\Foundation\Bootstrap\ConfigureLogging',//註冊異常處理
'Illuminate\Foundation\Bootstrap\HandleExceptions',//註冊服務容器的門面,Facade 是個提供從容器訪問物件的類。
'Illuminate\Foundation\Bootstrap\RegisterFacades',//註冊服務提供者
'Illuminate\Foundation\Bootstrap\RegisterProviders',//註冊服務提供者 `boot`
'Illuminate\Foundation\Bootstrap\BootProviders',];
複製程式碼
注意順序:
Facades
先於ServiceProviders
,Facades
也是重點,後面說,這裡簡單提一下,註冊Facades
就是註冊config\app.php
中的aliases
陣列,你使用的很多類,如Auth
,Cache
,DB
等等都是Facades
;而ServiceProviders
的register
方法永遠先於boot
方法執行,以免產生boot
方法依賴某個例項而該例項還未註冊的現象。
HTTP 核心還定義了一系列所有請求在處理前需要經過的 HTTP 中介軟體,這些中介軟體處理 HTTP 會話的讀寫、判斷應用是否處於維護模式、驗證 CSRF 令牌等等。
HTTP 核心的標誌性方法 handle處理的邏輯相當簡單:獲取一個
Request
,返回一個Response
,把該核心想象作一個代表整個應用的大黑盒子,輸入 HTTP 請求,返回 HTTP 響應。
第四步:將請求傳遞給路由。
在Laravel基礎的服務啟動之後,就要把請求傳遞給路由了。路由器將會分發請求到路由或控制器,同時執行所有路由指定的中介軟體。
傳遞給路由是通過 Pipeline
(管道)來傳遞的,但是Pipeline有一堵牆,在傳遞給路由之前所有請求都要經過,這堵牆定義在app\Http\Kernel.php
中的$middleware
陣列中,沒錯就是中介軟體,預設只有一個CheckForMaintenanceMode
中介軟體,用來檢測你的網站是否暫時關閉。這是一個全域性中介軟體,所有請求都要經過,你也可以新增自己的全域性中介軟體。
然後遍歷所有註冊的路由,找到最先符合的第一個路由,經過它的路由中介軟體,進入到控制器或者閉包函式,執行你的具體邏輯程式碼。
所以,當請求到達你寫的程式碼之前,Laravel已經做了大量工作,請求也經過了千難萬險,那些不符合或者惡意的的請求已被Laravel隔離在外。
處理請求到響應過程本文來自:簡書
感謝作者:伊Summer
檢視原文:Laravel 的生命週期