“
本文會對控制器最后的執行流程和使用的倆個高級屬性進行簡單的學習,一個是fastcgi_finish_request方法巧用,另一個是trait特性,超類的概念多少都有過了解,接下來一起來解析一下。
”
一、如何輸出數據到終端
當執行完控制器中的方法響應數據給App類的run方法,直到這里就已經執行完了。
是不是有點懵這里的數據最終會返回哪里呢!
之前寫過的框架執行流程、路由、控制器實例化都是從這里開始進入的。
所以當run方法執行完成之后,就會把對應的結果給返回到這里。
這一部分的代碼Container::get(‘app’)應該都知道了是返回一個App類的實例。
然后通過App類去執行run方法,才會有之前講過的一切。
下圖是咔咔從半中腰做的一個思維導圖,前面的沒有,后邊的所有知識點都會寫在這個思維導圖里。
執行完run方法就會去執行Container::get(‘app’)->run()->send()send這個方法,有多少人會認為在App類里邊執行send方法。
其實不是的,回想一下之前執行控制器方法然后返回的響應結果是什么?
如果你不是很粗略的看都會記得是Response的一個對象實例。
所以說send方法會去response類里邊去執行。
先不看其它的,先看這行代碼$this->app[‘hook’],現在知道是執行的那里嗎?
這種形式就是通過訪問數組形式去訪問對象的屬性,也就是之前解析的ArrayAccess這個類。當訪問的屬性不存在時會去執行offsetGet,然后執行魔術方法__get,最終通過make方法返回實例,這一切的操作都是在容器中。
對這行代碼具體是監聽的什么就不去做解析了。
接著需要看處理輸出數據的這行代碼$data = $this->getContent();
這個方法做的事情就是將傳過來的數據賦值給本類的content屬性。
立即學習“PHP免費學習筆記(深入)”;
其實在獲取輸出數據這個方法中,請看咔咔圈出來的第一個地方感覺是很沒有必要。
可以看到根本對數據就沒有任何的處理,只是簡單的返回了,所以說框架有好的地方也有不好的地方,只有你去閱讀了才會知道,否則你會對你經常使用的工具一無所知。
在接著就是Trace調試注入,就是通過配置文件配置的,通過調用debug類實現的,這里就不詳解了。
然后就是緩存判斷,緩存會在后文中單獨拎出來講,所以也是過。
在接下來就對響應頭的設置了,檢測 http 頭是否已經發送,這塊的東西就很重要了,也是平時接觸不多的知識點了。
-
headers_sent() : 檢測 HTTP 頭是否已經發送 -
http_response_code() :獲取/設置響應的 HTTP 狀態碼 -
header : 函數向客戶端發送原始的 HTTP 報頭。
最后一步,來了來了,它來了,它帶著echo來了,執行了一個方法$this->sendData($data);
給人一種媳婦熬成娘的感覺,終于來到的終點站,一個echo輸出了咔咔幾十天的心酸啊!
為了到達這個echo咔咔是經歷九九八十一難啊!戰斗還未停止,同志仍需努力啊!
那么到這里關于框架執行然后到應用初始化,在到路由檢測、控制器的實例化、然后返回response實例,在通過入口文件執行send方法。
最后將數據輸出到終端,也就是一個echo的事情。
雖然這里的戰斗結束了,但是在下面還有一個非常重要的知識點,咔咔將重新提一節來進行說明。
二、fastcgi_finish_request方法巧用
在上一節中通過Container::get(‘app’)->run()->send();在response類中執行了send方法,輸出了數據。
但是在輸出數據之后還執行了一個方法fastcgi_finish_request();,給的注釋是提高頁面響應,接下來好好來扒一扒其中的奧秘。
在php官網中看到這樣一段話
The script will still occupy a FPM process after fastcgi_finish_request(). So using it excessively for long running tasks may occupy all your FPM threads up to pm.max_children. This will lead to gateway errors on the webserver.
在fastcgi_finish_request()之后,腳本仍將占用FPM進程。 因此,對于長時間運行的任務過度使用它可能會占用您的所有FPM線程,直到pm.max_children。 這將導致Web服務器上的網關錯誤。
所以說在沒有徹底的了解這個方法之前不要輕易的在自己的項目中使用這個方法。
接下來咔咔將使用一個案例來演示這個方法的使用,僅僅只是演示使用,如果需要使用到項目中請仔細閱讀文檔應該注意的問題。
案例演示
公司有一個業務需要發送通知給用戶,但是由于發送時間太久,非常費時間,有可能需要好幾十秒的時間,更嚴重的會直接導致瀏覽器連接超時。
在一個問題就是用戶體驗的問題,用戶等待時間過程,體驗當然不好。
為了解決以上倆個問題,今天談論的fastcgi_finish_request就派上了用場。
理解
對這個函數的理解其實就是發送響應給瀏覽器,用戶等待時間大大縮短,但是PHP進程還是在運行的。
這樣就達到了來個目的,就類似于我們經常說的異步執行。
直觀的來說就是發送郵件有可能需要10秒,但是用戶是沒有感知的,用戶點擊發送郵件之后直接就返回發送成功,瀏覽器響應結束,用戶做其它事情,后臺進程繼續執行發送郵件的任務。
案例
具體代碼
<span style="display: block; background: url(" https: no-repeat rgb height: width: margin-bottom: border-radius:></span><span class="hljs-meta" style="color: rgb(97, 174, 238); line-height: 26px;"><?php </span><br><span class="hljs-comment" style="color: rgb(92, 99, 112); font-style: italic; line-height: 26px;">/**<br>?*?設置超時時間,變成不限制<br>?*<br>?*/</span><br>set_time_limit(<span class="hljs-number" style="color: rgb(209, 154, 102); line-height: 26px;">0</span>);<br><br><span class="hljs-comment" style="color: rgb(92, 99, 112); font-style: italic; line-height: 26px;">/**<br>?*?本函數模擬非常耗時的任務,執行完畢需要5秒的時間<br>?*/</span><br><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: rgb(198, 120, 221); line-height: 26px;">function</span>?<span class="hljs-title" style="color: rgb(97, 174, 238); line-height: 26px;">writeFile</span><span class="hljs-params" style="line-height: 26px;">()</span><br></span>{<br>????$path?=?<span class="hljs-string" style="color: rgb(152, 195, 121); line-height: 26px;">'D:/phpstudy_pro/WWW/kaka.txt'</span>;<br>????file_put_contents($path,<span class="hljs-string" style="color: rgb(152, 195, 121); line-height: 26px;">'程序運行開始'</span>?.?PHP_EOL,FILE_APPEND);<br>????<span class="hljs-keyword" style="color: rgb(198, 120, 221); line-height: 26px;">for</span>($i?=<span class="hljs-number" style="color: rgb(209, 154, 102); line-height: 26px;">0</span>;$i?5</span>;$i++)?{<br>????????file_put_contents($path,time()?.?PHP_EOL,FILE_APPEND);<br>????????sleep(<span class="hljs-number" style="color: rgb(209, 154, 102); line-height: 26px;">1</span>);<br>????}<br><br>????file_put_contents($path,<span class="hljs-string" style="color: rgb(152, 195, 121); line-height: 26px;">'程序運行結束'</span>?.?PHP_EOL,FILE_APPEND);<br><br>}<br><br><span class="hljs-comment" style="color: rgb(92, 99, 112); font-style: italic; line-height: 26px;">/**<br>?*?輸出文字標記,任務開始<br>?*/</span><br><span class="hljs-keyword" style="color: rgb(198, 120, 221); line-height: 26px;">echo</span>(<span class="hljs-string" style="color: rgb(152, 195, 121); line-height: 26px;">'任務開始'</span>);<br><br><span class="hljs-comment" style="color: rgb(92, 99, 112); font-style: italic; line-height: 26px;">/**<br>?*??后臺執行非常耗時的任務<br>?*/</span><br>register_shutdown_function(writeFile);<br><br><span class="hljs-comment" style="color: rgb(92, 99, 112); font-style: italic; line-height: 26px;">/**<br>?*?立即發送請求<br>?*/</span><br>fastcgi_finish_request();<br><br><br><br>
以上測試全部使用linux系統進行測試哈,否則你看不到直觀的效果。
經過上面的演示,響應非常快,瀏覽器響應結束后,后臺程序依然進行執行每秒執行一個時間戳。