PHP 非同步呼叫 後台調用 持續執行 中斷連線/瀏覽器
標題很怪,因為我也不知道怎樣用一句簡短的話來概括下面這部分內容。只是希望各位 PHP 的開發人員們更容易通過搜尋引擎搜到這篇介紹。
這回的核心內容就是圍繞 ignore_user_abort 這個函數展開的。
做? Web 開發的人都知道,瀏覽器和伺服器之間是通過 HTTP 協議進行串連通訊的。這是一種基於請求和響應模型的協議。瀏覽器通過 URL 向某台伺服器發起請求(Request),Web 服務器接收到請求,執行一段程式,然後做出響應(Response),也就是一段字串,這個字串符合 HTTP 協議的格式,有 HEAD 和 BODY 兩部分。
這其中有一個問題,Web? 伺服器執行一段程式,可能幾毫秒就完成,也可能幾分鐘都完不成。如果程式執行緩慢,使用者可能沒有耐心等下去,就關閉瀏覽器了。這個時候,伺服器會接收到串連狀態改變的通知,因為 HTTP? 是最上層的協議,下面還有一層 TCP 協議,TCP? 會知道串連中斷。串連一斷,服務端的程式會立即停止執行。
現在說到問題的關鍵了,服務端的程式立即停止執行,如果這個程式只是讀取資訊的還好說,停了就不讀了唄。萬一是一個寫入的程式呢?比如,使用者提交一段文本,也許服務端的設計比較複雜,需要同時更新好幾個表,但由於某些原因,例如其中一個表被其他進程鎖定,那麼這個程式就會一直等待,這個時候使用者要是關閉瀏覽器,那程式就不等了,直接退出了。結果就是這條資訊儲存不完整。
舉個具體的例子,使用者提交的文本需要寫到 A、B、C、D 四個表裡,寫入 A、B 兩個表可能 0.1 毫秒就完成了,但 C 表被另一個進程鎖定,那當前進程就得一直等,這時使用者關閉瀏覽器,當前進程退出,那麼,就會造成一種狀況,A、B 表裡有新的內容,而 C、D 表裡沒有這條內容,產生了嚴重的資料一致性的問題!
雖然,利用資料庫的事務,可以使狀態復原,但結果就是使用者的本次提交無效。
我希望的是,只要使用者提交了,就要成功儲存,也許遇到意外情況導致執行時間過長,但使用者關閉瀏覽器也沒關係。
於是,我找到了 ignore_user_abort 這個函數。
當調用 ignore_user_abort(1) 時, 就設定了忽略使用者退出這個標誌位,也就是不管怎樣,也要把程式執行到底,除非在程式中調用了 exit。
其實,還有另一個函數,register_shutdown_function,它可以註冊一個函數或方法,在程式退出的時候調用,有些類似於 javascript 裡面的 onunload 和 onbeforeunload 事件。
我這裡引用了 中文版PHP手冊 的相關內容:
章 40. 串連處理
注意: 以下內容對 PHP 3.0.7 及更高版本適用。
在 PHP 內部,系統維護著串連狀態,其狀態有三種可能的情況:
0 - NORMAL(正常)
1 - ABORTED(異常退出)
2 - TIMEOUT(逾時)
當 PHP 指令碼正常地運行 NORMAL 狀態時,串連為有效。當遠程用戶端中斷串連時,ABORTED 狀態的標記將會被開啟。遠程用戶端串連的中斷通常是由使用者點擊 STOP 按鈕導致的。當連線時間超過 PHP 的時限(請參閱 set_time_limit() 函數)時,TIMEOUT 狀態的標記將被開啟。
可以決定指令碼是否需要在用戶端中斷串連時退出。有時候讓指令碼完整地運行會帶來很多方便,即使沒有遠程瀏覽器接受指令碼的輸出。預設的情況是當遠程用戶端串連中斷時指令碼將會退出。該處理過程可由 php.ini 的 ignore_user_abort 或由 Apache .conf 設定中對應的“php_value ignore_user_abort”以及 ignore_user_abort() 函數來控制。如果沒有告訴 PHP 忽略使用者的中斷,指令碼將會被中斷,除非通過 register_shutdown_function() 設定了關閉觸發函數。通過該關閉觸發函數,當遠端使用者點擊 STOP 按鈕後,指令碼再次嘗試輸出資料時,PHP 將會檢測到串連已被中斷,並調用關閉觸發函數。
指令碼也有可能被內建的指令碼計時器中斷。預設的逾時限制為 30 秒。這個值可以通過設定 php.ini 的 max_execution_time 或 Apache .conf 設定中對應的“php_value max_execution_time”參數或者 set_time_limit() 函數來更改。當計數器逾時的時候,指令碼將會類似於以上串連中斷的情況退出,先前被註冊過的關閉觸發函數也將在這時被執行。在該關閉觸發函數中,可以通過調用 connection_status() 函數來檢查逾時是否導致關閉觸發函數被調用。如果逾時導致了關閉觸發函數的調用,該函數將返回 2。
需要注意的一點是 ABORTED 和 TIMEOUT 狀態可以同時有效。這在告訴 PHP 忽略使用者的退出操作時是可能的。PHP 將仍然注意使用者已經中斷了串連但指令碼仍然在啟動並執行情況。如果到了啟動並執行時間限制,指令碼將被退出,設定過的關閉觸發函數也將被執行。在這時會發現函數 connection_status() 返回 3。
PHP 的官方網站線上文檔有英文原版說明,下面還有一些使用者的反饋,也很有價值,這裡是連結:
?http://www.php.net/manual/en/features.connection-handling.php
轉自:http://www.leakon.com/archives/22