世間萬物皆有生命周期潮瓶,當(dāng)我們使用任何工具時都需要理解它的工作原理,那么用起來就會得心應(yīng)手毯辅,應(yīng)用開發(fā)也是如此。理解了它的原理思恐,那么使用起來就會游刃有余。
在了解 Laravel 的生命周期前基跑,我們先回顧一下PHP 的生命周期。
PHP 的生命周期
PHP 的運(yùn)行模式
PHP兩種運(yùn)行模式是WEB模式媳否、CLI模式。
- 當(dāng)我們在終端敲入php這個命令的時候篱竭,使用的是CLI模式力图。
- 當(dāng)使用Nginx或者別web服務(wù)器作為宿主處理一個到來的請求時,使用的是WEB模式掺逼。
生命周期
當(dāng)我們請求一個php
文件時,PHP 為了完成這次請求,會發(fā)生5個階段的生命周期切換:
模塊初始化(MINIT)吕喘,即調(diào)用
php.ini
中指明的擴(kuò)展的初始化函數(shù)進(jìn)行初始化工作,如mysql
擴(kuò)展兽泄。請求初始化(RINIT),即初始化為執(zhí)行本次腳本所需要的變量名稱和變量值內(nèi)容的符號表病梢,如
$_SESSION
變量。執(zhí)行該P(yáng)HP腳本蜓陌。
請求處理完成(Request Shutdown),按順序調(diào)用各個模塊的
RSHUTDOWN
方法填抬,對每個變量調(diào)用unset
函數(shù),如unset $_SESSION
變量飒责。關(guān)閉模塊(Module Shutdown) , PHP調(diào)用每個擴(kuò)展的
MSHUTDOWN
方法宏蛉,這是各個模塊最后一次釋放內(nèi)存的機(jī)會。這意味著沒有下一個請求了拾并。
WEB模式和CLI(命令行)模式很相似,區(qū)別是:
- CLI 模式會在每次腳本執(zhí)行經(jīng)歷完整的5個周期嗅义,因?yàn)槟隳_本執(zhí)行完不會有下一個請求隐砸;
- WEB模式為了應(yīng)對并發(fā)之碗,可能采用多線程凰萨,因此生命周期
1
和5
有可能只執(zhí)行一次械馆,下次請求到來時重復(fù)2-4
的生命周期,這樣就節(jié)省了系統(tǒng)模塊初始化所帶來的開銷霹崎。
可以看出PHP生命周期是很對稱的冶忱。說了這么多尾菇,就是為了定位Laravel運(yùn)行在哪里囚枪,沒錯,Laravel僅僅運(yùn)行再 第三個階段:
作用
理解這些链沼,你就可以優(yōu)化你的 Laravel
代碼,可以更加深入的了解 Laravel 的singleton
(單例)括勺。至少你知道了,每一次請求結(jié)束疾捍,PHP 的變量都會 unset
,Laravel 的 singleton
只是在某一次請求過程中的singleton
乱豆;你在 Laravel 中的靜態(tài)變量也不能在多個請求之間共享,因?yàn)槊恳淮握埱蠼Y(jié)束都會 unset
宛裕。理解這些概念,是寫高質(zhì)量代碼的第一步翰守,也是最關(guān)鍵的一步。因此記住,PHP是一種腳本語言了袁,所有的變量只會在這一次請求中生效,下次請求之時已被重置载绿,而不像Java靜態(tài)變量擁有全局作用。
Laravel 的生命周期
概述
Laravel 的生命周期從public\index.php
開始崭庸,從public\index.php
結(jié)束谊囚。
下面是 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);
以下是四步詳細(xì)的解釋是:
composer自動加載需要的類
文件載入composer生成的自動加載設(shè)置执赡,包括所有你
composer require
的依賴镰踏。生成容器Container沙合,Application實(shí)例,并向容器注冊核心組件(HttpKernel首懈,ConsoleKernel ,ExceptionHandler)(對應(yīng)代碼2究履,容器很重要,后面詳細(xì)講解)最仑。
處理請求,生成并發(fā)送響應(yīng)(對應(yīng)代碼3盯仪,毫不夸張的說,你99%的代碼都運(yùn)行在這個小小的handle 方法里面)全景。
請求結(jié)束,進(jìn)行回調(diào)(對應(yīng)代碼4爸黄,還記得可終止中間件嗎?沒錯梆奈,就是在這里回調(diào)的)。
我們不妨在詳細(xì)一點(diǎn):
第一步:注冊加載composer自動生成的class loader
就是加載初始化第三方依賴亩钟。
第二步:生成容器 Container
并向容器注冊核心組件鳖轰,是從 bootstrap/app.php
腳本獲取 Laravel 應(yīng)用實(shí)例清酥,
第三步:這一步是重點(diǎn)蕴侣,處理請求,并生成發(fā)送響應(yīng)昆雀。
請求被發(fā)送到 HTTP
內(nèi)核或 Console
內(nèi)核蝠筑,這取決于進(jìn)入應(yīng)用的請求類型。
取決于是通過瀏覽器請求還是通過控制臺請求什乙。這里我們主要是通過瀏覽器請求。
HTTP 內(nèi)核的標(biāo)志性方法 handle處理的邏輯相當(dāng)簡單:獲取一個
Request
稳强,返回一個Response
,把該內(nèi)核想象作一個代表整個應(yīng)用的大黑盒子退疫,輸入 HTTP 請求,返回 HTTP 響應(yīng)褒繁。
1. 首先 Bootstrap 檢測環(huán)境馍忽,加載 bootstrapper
數(shù)組中的一些配置
HTTP 內(nèi)核繼承自 Illuminate\Foundation\Http\Kernel 類棒坏,該類定義了一個 bootstrappers 數(shù)組遭笋,這個數(shù)組中的類在請求被執(zhí)行前運(yùn)行,這些 bootstrappers 配置了錯誤處理瓦呼、日志、檢測應(yīng)用環(huán)境以及其它在請求被處理前需要執(zhí)行的任務(wù)央串。
protected $bootstrappers = [
//注冊系統(tǒng)環(huán)境配置 (.env)
'Illuminate\Foundation\Bootstrap\DetectEnvironment',
//注冊系統(tǒng)配置(config)
'Illuminate\Foundation\Bootstrap\LoadConfiguration',
//注冊日志配置
'Illuminate\Foundation\Bootstrap\ConfigureLogging',
//注冊異常處理
'Illuminate\Foundation\Bootstrap\HandleExceptions',
//注冊服務(wù)容器的門面,F(xiàn)acade 是個提供從容器訪問對象的類质和。
'Illuminate\Foundation\Bootstrap\RegisterFacades',
//注冊服務(wù)提供者
'Illuminate\Foundation\Bootstrap\RegisterProviders',
//注冊服務(wù)提供者 `boot`
'Illuminate\Foundation\Bootstrap\BootProviders',
];
注意順序:
Facades
先于ServiceProviders
,Facades
也是重點(diǎn)饲宿,后面說,這里簡單提一下瘫想,注冊Facades
就是注冊config\app.php
中的aliases
數(shù)組,你使用的很多類殿托,如Auth
剧蚣,Cache
,DB
等等都是Facades
旋廷;而ServiceProviders
的register
方法永遠(yuǎn)先于boot
方法執(zhí)行,以免產(chǎn)生boot
方法依賴某個實(shí)例而該實(shí)例還未注冊的現(xiàn)象饶碘。
HTTP 內(nèi)核還定義了一系列所有請求在處理前需要經(jīng)過的 HTTP 中間件馒吴,這些中間件處理 HTTP 會話的讀寫扎运、判斷應(yīng)用是否處于維護(hù)模式饮戳、驗(yàn)證 CSRF 令牌等等。
2. 第一堵墻扯罐,全局中間件,默認(rèn)為 CheckForMaintenanceMode
在Laravel基礎(chǔ)的服務(wù)啟動之后歹河,就要把請求傳遞給路由了。路由器將會分發(fā)請求到路由或控制器秸歧,同時運(yùn)行所有路由指定的中間件。
傳遞方式
傳遞給路由是通過 Pipeline
(管道)來傳遞的键菱,但是Pipeline有一堵墻,在傳遞給路由之前所有請求都要經(jīng)過纱耻,這堵墻定義在app\Http\Kernel.php
中的$middleware
數(shù)組中,沒錯就是中間件弄喘,默認(rèn)只有一個CheckForMaintenanceMode
中間件,用來檢測你的網(wǎng)站是否暫時關(guān)閉蘑志。這是一個全局中間件,所有請求都要經(jīng)過急但,你也可以添加自己的全局中間件。
3. 然后遍歷所有注冊的路由波桩,找到最先符合的第一個路由
然后遍歷所有注冊的路由,找到最先符合的第一個路由镐躲,
4. 第二堵墻侍筛,通過該路由的中間件(組)
經(jīng)過該路由中間件撒穷,進(jìn)入到控制器或者閉包函數(shù)匣椰,執(zhí)行你的具體邏輯代碼端礼。
所以禽笑,當(dāng)請求到達(dá)你寫的代碼之前蛤奥,Laravel已經(jīng)做了大量工作,請求也經(jīng)過了千難萬險喻括,那些不符合或者惡意的的請求已被Laravel隔離在外。