世間萬物皆有生命周期,當我們使用任何工具時都需要理解它的工作原理,,那么用起來就會得心應手,,應用開發(fā)也是如此。理解了它的原理,,那么使用起來就會游刃有余,。 Laravel是一套簡潔的PHP Web開發(fā)框架(PHP Web Framework),今天,,我們就來了解 一下Laravel 的生命周期,。在此之前,我們先回顧一下PHP 的生命周期,。 PHP 的生命周期生命周期當我們請求一個php文件時,PHP 為了完成這次請求,,會發(fā)生5個階段的生命周期切換: 模塊初始化(MINIT),即調用 php.ini 中指明的擴展的初始化函數(shù)進行初始化工作,,如 mysql 擴展,。 請求初始化(RINIT),即初始化為執(zhí)行本次腳本所需要的變量名稱和變量值內(nèi)容的符號表,,如 $_SESSION變量,。 執(zhí)行該PHP腳本。 請求處理完成(Request Shutdown),,按順序調用各個模塊的 RSHUTDOWN 方法,,對每個變量調用 unset函數(shù),如 unset $_SESSION 變量,。 關閉模塊(Module Shutdown) ,, PHP調用每個擴展的 MSHUTDOWN 方法,這是各個模塊最后一次釋放內(nèi)存的機會,。這意味著沒有下一個請求了,。
PHP 的運行模式當我們在終端敲入php這個命令的時候,使用的是CLI模式,。 當使用Nginx或者別web服務器作為宿主處理一個到來的請求時,使用的是WEB模式。 WEB模式和CLI(命令行)模式很相似,,區(qū)別是:WEB模式為了應對并發(fā),,可能采用多線程,因此生命周期1和5有可能只執(zhí)行一次,,下次請求到來時重復2-4的生命周期,,這樣就節(jié)省了系統(tǒng)模塊初始化所帶來的開銷,。 CLI 模式會在每次腳本執(zhí)行經(jīng)歷完整的5個周期,因為你腳本執(zhí)行完不會有下一個請求,。 可以看出PHP生命周期是很對稱的,。說了這么多,就是為了定位Laravel運行在哪里,,沒錯,,Laravel僅僅運行再 第三個階段: 理解這些,你就可以優(yōu)化你的 Laravel 代碼,,可以更加深入的了解 Laravel 的singleton(單例),。至少你知道了,每一次請求結束,,PHP 的變量都會 unset,,Laravel 的 singleton 只是在某一次請求過程中的singleton;你在 Laravel 中的靜態(tài)變量也不能在多個請求之間共享,,因為每一次請求結束都會 unset,。理解這些概念,是寫高質量代碼的第一步,,也是最關鍵的一步,。因此記住,,PHP是一種腳本語言,所有的變量只會在這一次請求中生效,,下次請求之時已被重置,,而不像Java靜態(tài)變量擁有全局作用,。
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 require的依賴,。 生成容器Container,Application實例,,并向容器注冊核心組件(HttpKernel,,ConsoleKernel ,ExceptionHandler)(對應代碼2,,容器很重要,,后面詳細講解),。 處理請求,,生成并發(fā)送響應(對應代碼3,,毫不夸張的說,你99%的代碼都運行在這個小小的handle 方法里面),。 請求結束,,進行回調(對應代碼4,還記得可終止中間件嗎,?沒錯,,就是在這里回調的)。
Laravel 的請求步驟,,我們不妨在詳細一點:
第一步:注冊加載composer自動生成的class loader
第二步:生成容器 Container并向容器注冊核心組件,是從 bootstrap/app.php 腳本獲取 Laravel 應用實例,。
這一步是重點,,處理請求,并生成發(fā)送響應,。請求被發(fā)送到 HTTP 內(nèi)核或 Console 內(nèi)核,,這取決于進入應用的請求類型。
取決于是通過瀏覽器請求還是通過控制臺請求,。這里我們主要是通過瀏覽器請求,。HTTP 內(nèi)核繼承自 Illuminate\Foundation\Http\Kernel 類,該類定義了一個 bootstrappers 數(shù)組,,這個數(shù)組中的類在請求被執(zhí)行前運行,,這些 bootstrappers 配置了錯誤處理、日志,、檢測應用環(huán)境以及其它在請求被處理前需要執(zhí)行的任務,。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', //注冊服務容器的門面,F(xiàn)acade 是個提供從容器訪問對象的類,。 'Illuminate\Foundation\Bootstrap\RegisterFacades', //注冊服務提供者 'Illuminate\Foundation\Bootstrap\RegisterProviders', //注冊服務提供者 `boot` 'Illuminate\Foundation\Bootstrap\BootProviders', ];
注意順序:Facades 先于ServiceProviders,,F(xiàn)acades也是重點,后面說,,這里簡單提一下,,注冊 Facades就是注冊 config\app.php中的aliases 數(shù)組,你使用的很多類,,如Auth,,Cache,DB等等都是Facades,;而ServiceProviders的register方法永遠先于boot方法執(zhí)行,以免產(chǎn)生boot方法依賴某個實例而該實例還未注冊的現(xiàn)象,。 HTTP 內(nèi)核還定義了一系列所有請求在處理前需要經(jīng)過的 HTTP 中間件,,這些中間件處理 HTTP 會話的讀寫、判斷應用是否處于維護模式,、驗證 CSRF 令牌等等,。HTTP 內(nèi)核的標志性方法 handle處理的邏輯相當簡單:獲取一個 Request,返回一個Response,,把該內(nèi)核想象作一個代表整個應用的大黑盒子,,輸入 HTTP 請求,返回 HTTP 響應,。 第四步:將請求傳遞給路由在Laravel基礎的服務啟動之后,,就要把請求傳遞給路由了。路由器將會分發(fā)請求到路由或控制器,,同時運行所有路由指定的中間件,。傳遞給路由是通過 Pipeline(管道)來傳遞的,但是Pipeline有一堵墻,,在傳遞給路由之前所有請求都要經(jīng)過,,這堵墻定義在app\Http\Kernel.php中的$middleware數(shù)組中,沒錯就是中間件,,默認只有一個CheckForMaintenanceMode中間件,,用來檢測你的網(wǎng)站是否暫時關閉。這是一個全局中間件,,所有請求都要經(jīng)過,,你也可以添加自己的全局中間件。然后遍歷所有注冊的路由,,找到最先符合的第一個路由,,經(jīng)過它的路由中間件,進入到控制器或者閉包函數(shù),,執(zhí)行你的具體邏輯代碼。所以,,當請求到達你寫的代碼之前,,Laravel已經(jīng)做了大量工作,請求也經(jīng)過了千難萬險,,那些不符合或者惡意的的請求已被Laravel隔離在外,。
|