說明
前面所有分析,都是從$response = $http->run();
展開的,經歷了漫漫長路,run
方法終於執行完畢,返回一個Response
物件,程式又回到入口檔案:
.
.
.
$response = $http->run();
$response->send();
$http->end($response);
接下來是執行$response->send();
。send
方法:
public function send(): void
{
// 處理輸出資料
$data = $this->getContent();
// 如果還沒有傳送響應頭且$this->header不為空
if (!headers_sent() && !empty($this->header)) {
// 傳送狀態碼
http_response_code($this->code);
// 傳送頭部資訊
foreach ($this->header as $name => $val) {
header($name . (!is_null($val) ? ':' . $val : ''));
}
}
// 儲存cookie
$this->cookie->save();
// 輸出資料
$this->sendData($data);
// 參考:http://www.laruence.com/2011/04/13/1991.html
if (function_exists('fastcgi_finish_request')) {
// 提高頁面響應
fastcgi_finish_request();
}
}
過程比較簡單:傳送狀態碼、傳送響應頭,然後傳送響應內容。
收尾工作
接著是執行:$http->end($response);
,展開如下:
public function end(Response $response): void
{
//觸發HttpEnd事件
$this->app->event->trigger('HttpEnd', $response);
// 寫入日誌
$this->app->log->save();
// 寫入Session
$this->app->session->save();
}
以上程式碼執行完了之後,整個生命週期本該結束了,發現程式竟然還繼續執行think\initializer\Error
類的appShutdown
方法:
public function appShutdown(): void
{
if (!is_null($error = error_get_last()) && $this->isFatal($error['type'])) {
// 將錯誤資訊託管至think\ErrorException
$exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']);
$this->appException($exception);
}
}
開始是想可能是解構函式呼叫了它,但也沒有到有解構函式呼叫。最後發現,原來前面應用初始化的時候,載入了think\initializer\Error
類,並執行了init
方法:
public function init(App $app)
{
$this->app = $app;
//開啟所有級別錯誤提示
error_reporting(E_ALL);
//設定自定義的函式處理執行中的錯誤
set_error_handler([$this, 'appError']);
//設定預設的異常處理程式,用於沒有用 try/catch 塊來捕獲的異常
set_exception_handler([$this, 'appException']);
//註冊一個 callback ,它會在指令碼執行完成或者 exit() 後被呼叫。
register_shutdown_function([$this, 'appShutdown']);
}
該方法最後一行註冊了一個回撥,它會在指令碼執行完成或者 exit() 後被呼叫。
生命週期小結
至此,一個精簡版的請求生命就結束了。一路下來,不停地單步執行、回放,像是程式碼在大腦裡一遍又一遍執行,還好堅持了下來。一個生命週期分析了一遍,還是有很大收穫的。後面計劃分析:事件機制、服務、Facade、模型、驗證器。