小編給大家分享一下ThinkPHP框架如何使用fastcgi_finish_request和trait,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
創(chuàng)新互聯(lián)專注于平定企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站,商城建設(shè)。平定網(wǎng)站建設(shè)公司,為平定等地區(qū)提供建站服務(wù)。全流程定制網(wǎng)站制作,專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)
當(dāng)執(zhí)行完控制器中的方法響應(yīng)數(shù)據(jù)給App類的run方法,直到這里就已經(jīng)執(zhí)行完了。
是不是有點(diǎn)懵這里的數(shù)據(jù)最終會(huì)返回哪里呢!
之前寫(xiě)過(guò)的框架執(zhí)行流程、路由、控制器實(shí)例化都是從這里開(kāi)始進(jìn)入的。
所以當(dāng)run方法執(zhí)行完成之后,就會(huì)把對(duì)應(yīng)的結(jié)果給返回到這里。
這一部分的代碼Container::get('app')
應(yīng)該都知道了是返回一個(gè)App類的實(shí)例。
然后通過(guò)App類去執(zhí)行run方法,才會(huì)有之前講過(guò)的一切。
下圖是咔咔從半中腰做的一個(gè)思維導(dǎo)圖,前面的沒(méi)有,后邊的所有知識(shí)點(diǎn)都會(huì)寫(xiě)在這個(gè)思維導(dǎo)圖里。
執(zhí)行完run方法就會(huì)去執(zhí)行Container::get('app')->run()->send()
send這個(gè)方法,有多少人會(huì)認(rèn)為在App類里邊執(zhí)行send方法。
其實(shí)不是的,回想一下之前執(zhí)行控制器方法然后返回的響應(yīng)結(jié)果是什么?
如果你不是很粗略的看都會(huì)記得是Response的一個(gè)對(duì)象實(shí)例。
所以說(shuō)send方法會(huì)去response類里邊去執(zhí)行。
先不看其它的,先看這行代碼$this->app['hook']
,現(xiàn)在知道是執(zhí)行的那里嗎?
這種形式就是通過(guò)訪問(wèn)數(shù)組形式去訪問(wèn)對(duì)象的屬性,也就是之前解析的ArrayAccess這個(gè)類。當(dāng)訪問(wèn)的屬性不存在時(shí)會(huì)去執(zhí)行offsetGet,然后執(zhí)行魔術(shù)方法__get,最終通過(guò)make方法返回實(shí)例,這一切的操作都是在容器中。
對(duì)這行代碼具體是監(jiān)聽(tīng)的什么就不去做解析了。
接著需要看處理輸出數(shù)據(jù)的這行代碼$data = $this->getContent();
這個(gè)方法做的事情就是將傳過(guò)來(lái)的數(shù)據(jù)賦值給本類的content屬性。
其實(shí)在獲取輸出數(shù)據(jù)這個(gè)方法中,請(qǐng)看咔咔圈出來(lái)的第一個(gè)地方感覺(jué)是很沒(méi)有必要。
可以看到根本對(duì)數(shù)據(jù)就沒(méi)有任何的處理,只是簡(jiǎn)單的返回了,所以說(shuō)框架有好的地方也有不好的地方,只有你去閱讀了才會(huì)知道,否則你會(huì)對(duì)你經(jīng)常使用的工具一無(wú)所知。
在接著就是Trace調(diào)試注入,就是通過(guò)配置文件配置的,通過(guò)調(diào)用debug類實(shí)現(xiàn)的,這里就不詳解了。
然后就是緩存判斷,緩存會(huì)在后文中單獨(dú)拎出來(lái)講,所以也是過(guò)。
在接下來(lái)就對(duì)響應(yīng)頭的設(shè)置了,檢測(cè) HTTP 頭是否已經(jīng)發(fā)送,這塊的東西就很重要了,也是平時(shí)接觸不多的知識(shí)點(diǎn)了。
最后一步,來(lái)了來(lái)了,它來(lái)了,它帶著echo來(lái)了,執(zhí)行了一個(gè)方法$this->sendData($data);
給人一種媳婦熬成娘的感覺(jué),終于來(lái)到的終點(diǎn)站,一個(gè)echo輸出了咔咔幾十天的心酸啊!
為了到達(dá)這個(gè)echo咔咔是經(jīng)歷九九八十一難啊!戰(zhàn)斗還未停止,同志仍需努力??!
那么到這里關(guān)于框架執(zhí)行然后到應(yīng)用初始化,在到路由檢測(cè)、控制器的實(shí)例化、然后返回response實(shí)例,在通過(guò)入口文件執(zhí)行send方法。
最后將數(shù)據(jù)輸出到終端,也就是一個(gè)echo的事情。
雖然這里的戰(zhàn)斗結(jié)束了,但是在下面還有一個(gè)非常重要的知識(shí)點(diǎn),咔咔將重新提一節(jié)來(lái)進(jìn)行說(shuō)明。
在上一節(jié)中通過(guò)Container::get('app')->run()->send();
在response類中執(zhí)行了send方法,輸出了數(shù)據(jù)。
但是在輸出數(shù)據(jù)之后還執(zhí)行了一個(gè)方法fastcgi_finish_request();
,給的注釋是提高頁(yè)面響應(yīng),接下來(lái)好好來(lái)扒一扒其中的奧秘。
在PHP官網(wǎng)中看到這樣一段話
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進(jìn)程。 因此,對(duì)于長(zhǎng)時(shí)間運(yùn)行的任務(wù)過(guò)度使用它可能會(huì)占用您的所有FPM線程,直到pm.max_children。 這將導(dǎo)致Web服務(wù)器上的網(wǎng)關(guān)錯(cuò)誤。
所以說(shuō)在沒(méi)有徹底的了解這個(gè)方法之前不要輕易的在自己的項(xiàng)目中使用這個(gè)方法。
接下來(lái)咔咔將使用一個(gè)案例來(lái)演示這個(gè)方法的使用,僅僅只是演示使用,如果需要使用到項(xiàng)目中請(qǐng)仔細(xì)閱讀文檔應(yīng)該注意的問(wèn)題。
案例演示
公司有一個(gè)業(yè)務(wù)需要發(fā)送通知給用戶,但是由于發(fā)送時(shí)間太久,非常費(fèi)時(shí)間,有可能需要好幾十秒的時(shí)間,更嚴(yán)重的會(huì)直接導(dǎo)致瀏覽器連接超時(shí)。
在一個(gè)問(wèn)題就是用戶體驗(yàn)的問(wèn)題,用戶等待時(shí)間過(guò)程,體驗(yàn)當(dāng)然不好。
為了解決以上倆個(gè)問(wèn)題,今天談?wù)摰?code>fastcgi_finish_request就派上了用場(chǎng)。
理解
對(duì)這個(gè)函數(shù)的理解其實(shí)就是發(fā)送響應(yīng)給瀏覽器,用戶等待時(shí)間大大縮短,但是PHP進(jìn)程還是在運(yùn)行的。
這樣就達(dá)到了來(lái)個(gè)目的,就類似于我們經(jīng)常說(shuō)的異步執(zhí)行。
直觀的來(lái)說(shuō)就是發(fā)送郵件有可能需要10秒,但是用戶是沒(méi)有感知的,用戶點(diǎn)擊發(fā)送郵件之后直接就返回發(fā)送成功,瀏覽器響應(yīng)結(jié)束,用戶做其它事情,后臺(tái)進(jìn)程繼續(xù)執(zhí)行發(fā)送郵件的任務(wù)。
案例
具體代碼
/**
* 設(shè)置超時(shí)時(shí)間,變成不限制
*
*/
set_time_limit(0);
/**
* 本函數(shù)模擬非常耗時(shí)的任務(wù),執(zhí)行完畢需要5秒的時(shí)間
*/
function writeFile()
{
$path = 'D:/phpstudy_pro/WWW/kaka.txt';
file_put_contents($path,'程序運(yùn)行開(kāi)始' . PHP_EOL,FILE_APPEND);
for($i =0;$i < 5;$i++) {
file_put_contents($path,time() . PHP_EOL,FILE_APPEND);
sleep(1);
}
file_put_contents($path,'程序運(yùn)行結(jié)束' . PHP_EOL,FILE_APPEND);
}
/**
* 輸出文字標(biāo)記,任務(wù)開(kāi)始
*/
echo('任務(wù)開(kāi)始');
/**
* 后臺(tái)執(zhí)行非常耗時(shí)的任務(wù)
*/
register_shutdown_function(writeFile);
/**
* 立即發(fā)送請(qǐng)求
*/
fastcgi_finish_request();
以上測(cè)試全部使用linux系統(tǒng)進(jìn)行測(cè)試哈,否則你看不到直觀的效果。
經(jīng)過(guò)上面的演示,響應(yīng)非??欤瑸g覽器響應(yīng)結(jié)束后,后臺(tái)程序依然進(jìn)行執(zhí)行每秒執(zhí)行一個(gè)時(shí)間戳。
以上就是對(duì)fastcgi_finish_request
方法的簡(jiǎn)單介紹,如果你也感興趣可以進(jìn)行簡(jiǎn)單的嘗試一下,有助于更好的去理解其中的小秘密。
應(yīng)該在倆年前咔咔就對(duì)這個(gè)特性進(jìn)行過(guò)一次解析,trait
就是常說(shuō)的超類。
這個(gè)特性是在PHP5.4才加入的,這個(gè)特性不是經(jīng)常使用的接口更不是類。
這個(gè)特性是為了解決PHP的一大弱點(diǎn)只能單繼承的缺點(diǎn),但是也不能叫多繼承,嚴(yán)謹(jǐn)一點(diǎn)的就是類似多繼承的功能而已。
接下來(lái)給大家演示一個(gè)案例。
創(chuàng)建test文件一,并且返回對(duì)應(yīng)類名。
創(chuàng)建test1文件,并且返回對(duì)應(yīng)類名
創(chuàng)建控制器文件用來(lái)輸出信息。
然后在控制器中引入對(duì)應(yīng)的超類文件,這里需要注意的是圈住的第一個(gè)框,這個(gè)框就是直接引入超類test文件。
然后可以直接進(jìn)行訪問(wèn),看會(huì)返回什么。
通過(guò)上圖訪問(wèn)結(jié)果結(jié)果可以看得到返回的是Test超類文件的方法,但是此控制器同樣也基礎(chǔ)了Controller控制器,這也就是在文章一開(kāi)頭就說(shuō)的超類就是實(shí)現(xiàn)了一種多繼承的功能而已。
但是這里會(huì)存在一個(gè)問(wèn)題,請(qǐng)看下圖報(bào)錯(cuò)信息。
上圖的報(bào)錯(cuò)信息是因?yàn)樵诳刂破髦惺褂昧藗z個(gè)超類導(dǎo)致的,也就是下圖的使用方式。
那么如何解決這種報(bào)錯(cuò)信息呢!接下來(lái)跟這咔咔的節(jié)奏一起來(lái)。
解決報(bào)錯(cuò)信息
在解決之前問(wèn)題之前得先清楚這個(gè)問(wèn)題是由于什么引起的。
出現(xiàn)這個(gè)錯(cuò)誤的原因是引用的兩個(gè)trait里面有同名的hello函數(shù),出現(xiàn)了沖突。
但是在日常開(kāi)發(fā)中這種情況都是可以避免的,因?yàn)槭謩?dòng)改方法名還是很方便的,但是這里咔咔教大家如何解決這種問(wèn)題。
一是用其中一個(gè)trait里的hello方法覆蓋另外一個(gè)trait的同名方法,因?yàn)閮蓚€(gè)方法內(nèi)容是一致的,所以我這里直接選擇insteadof覆蓋;
二是給他們用as起別名,這樣就不會(huì)有沖突了。as關(guān)鍵詞還有另外一個(gè)用途,那就是修改方法的訪問(wèn)控制。
經(jīng)過(guò)上圖的改動(dòng)之后,再一次的進(jìn)行訪問(wèn),看一下返回結(jié)果。
那么這個(gè)時(shí)候就會(huì)有伙伴有疑問(wèn)了,就是案例打印結(jié)果一直是Test類的方法,Test1類的方法一直沒(méi)有進(jìn)行打印。
那是如何進(jìn)行訪問(wèn)的呢!來(lái)接著看一下。
從上圖可以看到將訪問(wèn)方法改為了別名控制訪問(wèn),接著來(lái)看一下訪問(wèn)結(jié)果。
從上圖中可以可以看到返回結(jié)果就是超類Test1類的返回結(jié)果。
那么關(guān)于as這個(gè)的使用就需要大家在去搜索一下使用方式,有時(shí)候注意一下細(xì)節(jié)就可以學(xué)到很多知識(shí)點(diǎn)。
直到這里關(guān)于控制器的源碼解析就到這了,咔咔通過(guò)源碼給大家分析控制器的如如何進(jìn)行實(shí)例化的。
也再一次的進(jìn)行了對(duì)ArrayAccess和魔術(shù)方法的調(diào)用關(guān)系,一定要有自己的思考去想問(wèn)題。
在就是對(duì)訪問(wèn)控制器后是如何進(jìn)行響應(yīng)數(shù)據(jù)的,等等。
也在源碼中學(xué)到了關(guān)于fastcgi_finish_request方法巧用,但是在使用這個(gè)函數(shù)一定要注意關(guān)于咔咔提到的倆個(gè)注意點(diǎn)。
最后就是對(duì)超類的一個(gè)簡(jiǎn)單案例描述。
看完了這篇文章,相信你對(duì)“ThinkPHP框架如何使用fastcgi_finish_request和trait”有了一定的了解,如果想了解更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!