[TOC] # 说明 前面所有分析,都是从`$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 { $this->app->event->trigger(HttpEnd::class, $response); //执行中间件 // 由此可以看出,可以在中间件添加end方法,在程序结束时执行 $this->app->middleware->end($response); // 写入日志 $this->app->log->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。