PHP工做模型與運行機制

PHP的工做模型很是特殊。從某種程度上說,PHP和ASP、ASP.NET、JSP/Servlet等流行的Web技術,有着本質上的區別。php

以Java爲例,Java在Web應用領域,有兩種技術:Java Servlet和JSP(Java Server Page)。Java Servlet是一種特殊類型的Java程序,它經過實現相關接口,處理Web服務器發送過來的請求,完成相應的工做。JSP在形式上是一種相似於PHP的腳本,可是事實上,它最後也被編譯成Servlet。也就是說,在Java解決方案中,JSP和Servlet是做爲獨立的Java應用程序執行的,它們在初始化以後就駐留內存,經過特定的接口和Web服務器通訊,完成相應工做。除非被顯式地重啓,不然它們不會終止。所以,能夠在JSP和Servlet中使用各類緩存技術,例如數據庫鏈接池。mysql

ASP.NET的機制與此相似。至於ASP,雖然也是一種解釋型語言,可是仍然提供了Application對象來存放應用程序級的全局變量,它依託於ASP解釋器在IIS中駐留的進程,在整個應用程序的生命期有效。sql

PHP是一種純解釋型在服務端執行的能夠內嵌HTML的腳本語言,尤爲適合開發Web應用程序。數據庫

請求一個 PHP 腳本時,PHP 會讀取該腳本,並將其編譯爲 Zend 操做碼,這是要執行的代碼的一種二進制表示形式。隨後,此操做碼由 PHP 執行並丟棄。 PHP腳本在每次被解釋時進行初始化,在解釋完畢後終止運行。這種運行是互相獨立的,每一次請求都會建立一個單獨的進程或線程,來解釋相應的頁面文件。頁面建立的變量和其餘對象,都只在當前的頁面內部可見,沒法跨越頁面訪問

。在終止運行後,頁面中申請的、沒有被代碼顯式釋放的外部資源,包括內存、數據庫鏈接、文件句柄、Socket鏈接等,都會被強行釋放。也就是說,PHP沒法在語言級別上實現直接訪問跨越頁面的變量,也沒法建立駐留內存的對象。
設計模式

class StaticVarTester {
    public static $StaticVar = 0;
}
function TestStaticVar() {
    StaticVarTester :: $StaticVar += 1;
    echo "StaticVarTester :: StaticVar = " . StaticVarTester :: $StaticVar;
}
TestStaticVar();
echo "<br / >";
TestStaticVar();

在這個例子中,定義了一個名爲StaticVarTester的類,它僅有一個公共的靜態成員$StaticVar,並被初始化爲0。而後,在TestStaticVar()函數中,對StaticVarTester :: $StaticVar進行累加操做,並將它打印輸出。瀏覽器


熟悉Java或C++的開發者對這個例子應該並不陌生。$StaticVar做爲StaticVarTester類的一個靜態成員,只在類被裝載時進行初始化,不管StaticVarTester類被實例化多少次,$StaticVar都只存在一個實例,並且不會被屢次初始化。所以,當第一次調用TestStaticVar()函數時,$StaticVar進行了累加操做,值爲1,並被保存。第二次調用TestStaticVar()函數,$StaticVar的值爲2。緩存


打印出來的結果和咱們預料的同樣:服務器


1數據結構

StaticVarTester :: StaticVar = 1多線程

2

StaticVarTester :: StaticVar = 2

可是,當瀏覽器刷新頁面,再次執行這段代碼時,不一樣的狀況出現了。在Java或C++裏面,$StaticVar的值會被保存並一直累加下去,咱們將會看到以下的結果:


1

StaticVarTester :: StaticVar = 3

2

StaticVarTester :: StaticVar = 4

3

可是在PHP中,因爲上文敘及的機制,當前頁面每次都解釋時,都會執行一次程序初始化和終止的過程。也就是說,每次訪問時,StaticVarTester都會被從新裝載,而下列這行語句 public static $StaticVar = 0; 也會被重複執行。當頁面執行完成後,全部的內存空間都會被回收,$StaticVar這個變量(連同整個StaticVarTester類)也就不復存在。所以,不管刷新頁面多少次,$StaticVar變量都會回到起點:先被初始化爲0,而後在TestStaticVar()函數調用中被累加。因此,咱們看到的結果永遠是這個:


1

StaticVarTester :: StaticVar = 1

2

StaticVarTester :: StaticVar = 2

PHP這種獨特的工做模型的優點在於,基本上解決了使人頭疼的資源泄漏問題。Web應用的特色是大量的、短期的併發處理,對各類資源的申請和釋放工做很是頻繁,很容易致使泄漏甚至崩潰。PHP的運行機制決定它不存在常規的崩潰問題(頂多鏈接超時腳本中止執行),能夠說PHP是較穩定的Web應用。可是,這種機制的缺點也很是明顯。最直接的後果是,PHP在語言級別沒法實現跨頁面的緩衝機制。這種緩衝機制缺失形成的影響,能夠分紅兩個方面:


一是對象的緩衝。衆所周知,不少設計模式都依賴於對象的緩衝機制,建立和銷燬對象是很費時間的,由於建立一個對象要獲取內存資源或者其它更多資源,對於須要頻繁應付大量併發的服務端軟件更是如此。所以,對象緩衝的缺失,理論上會極大地下降速度。應儘量減小建立和銷燬對象的次數來提升服務程序的效率,因爲 PHP目前還不支持多線程,也就沒法像Java同樣經過線程池調度來彌補這一缺陷;但可使用第三方軟件如Memcachd來實現PHP的對象緩衝機制,達到減小對象建立和銷燬的時間來提升服務程序的效率。Memcachd將PHP編譯後的 操做碼緩存並在內存中保存這個操做碼,並在下一次調用該頁面時重用它,這會節省不少時間。比較經常使用的緩存還有有 eAccelerator,另外一種流行的 eAccelerator 替代工具是 Alternative PHP Cache(APC)。


二是數據庫鏈接的緩衝。對於MySQL,PHP提供了一種內置的數據庫緩衝機制,即用mysql_pconnect()代替mysql_connect() 來打開數據庫而已。PHP會自動回收被廢棄的數據庫鏈接,以供重複使用。在實際應用中,這種持久性數據庫鏈接每每會致使數據庫鏈接的僞泄漏現象:在某個時間,併發的數據庫鏈接過多,超過了MySQL的最大鏈接數,從而致使新的進程沒法鏈接數據庫。可是過一段時間,當併發數減小時,PHP會釋放掉一些鏈接,網站又會恢復正常。出現這種現象的緣由是,當使用pconnect時,Apache 的httpd進程會不釋放connect,而當Apache的httpd進程數超過了mysql的最大鏈接數時,就會出現沒法鏈接的狀況。所以,須要當心地調整Apache和Mysql的配置,以使Apache的httpd進程數不會超出MySQL的最大鏈接數。筆者通過實踐,在PHP5和 Oracle10g的鏈接中,因爲頻於數據庫鏈接,有時候還會出現數據庫丟失鏈接的狀況(Oracle官方有針對PHP的加強包,不知是否能夠解決此問題,筆者未試)。


PHP的工做模型便是缺點也是優點,從本質上說,這就是PHP 的獨特之處。


若以FastCGI模式運行php,解析php.ini、載入所有擴展並重初始化所有數據結構這些都只在進程啓動時發生一次。一個額外的好處是,持續數據庫鏈接能夠工做。Nginx+PHP(FastCGI)是個不錯的選擇。

相關文章
相關標籤/搜索