程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP基礎知識 >> php深度探討

php深度探討

編輯:PHP基礎知識
 
  • 我們從未手動開啟過PHP的相關進程,它是隨著Apache的啟動而運行的;
  • PHP通過mod_php5.so模塊和Apache相連(具體說來是SAPI,即服務器應用程序編程接口);
  • PHP總共有三個模塊:內核、Zend引擎、以及擴展層;
  • PHP內核用來處理請求、文件流、錯誤處理等相關操作;
  • Zend引擎(ZE)用以將源文件轉換成機器語言,然後在虛擬機上運行它;
  • 擴展層是一組函數、類庫和流,PHP使用它們來執行一些特定的操作。比如,我們需要mysql擴展來連接MySQL數據庫;
  • 當ZE執行程序時可能會需要連接若干擴展,這時ZE將控制權交給擴展,等處理完特定任務後再返還;
  • 最後,ZE將程序運行結果返回給PHP內核,它再將結果傳送給SAPI層,最終輸出到浏覽器上。

深入探討
  等等,沒有這麼簡單。以上過程只是個簡略版,讓我們再深入挖掘一下,看看幕後還發生了些什麼。

  • Apache啟動後,PHP解釋程序也隨之啟動;
  • PHP的啟動過程有兩步;
  • 第一步是初始化一些環境變量,這將在整個SAPI生命周期中發生作用;
  • 第二步是生成只針對當前請求的一些變量設置。

PHP啟動第一步
  不清楚什麼第一第二步是什麼?別擔心,我們接下來詳細討論一下。讓我們先看看第一步,也是最主要的一步。要記住的是,第一步的操作在任何請求到達之前就發生了。

  • 啟動Apache後,PHP解釋程序也隨之啟動;
  • PHP調用各個擴展的MINIT方法,從而使這些擴展切換到可用狀態。看看php.ini文件裡打開了哪些擴展吧;
  • MINIT的意思是“模塊初始化”。各個模塊都定義了一組函數、類庫等用以處理其他請求。

  一個典型的MINIT方法如下:
PHP_MINIT_FUNCTION(extension_name){
/* Initialize functions, classes etc */
}
PHP啟動第二步

  • 當一個頁面請求發生時,SAPI層將控制權交給PHP層。於是PHP設置了用於回復本次請求所需的環境變量。同時,它還建立一個變量表,用來存放執行過程中產生的變量名和值。
  • PHP調用各個模塊的RINIT方法,即“請求初始化”。一個經典的例子是Session模塊的RINIT,如果在php.ini中啟用了Session模塊,那在調用該模塊的RINIT時就會初始化$_SESSION變量,並將相關內容讀入;
  • RINIT方法可以看作是一個准備過程,在程序執行之間就會自動啟動。

一、開篇

在開始這個專題之前,先說一點題外話。大多數人學習編程語言的時候,首先關注的是這種語言的語法及其常用函數。我學習C,Java,Php等語言就是按照這樣的方式開始的。一般情況下,這個階段需要一個月左右的時間就會完全掌握,並能基本熟練地使用。對於已有經驗的同學,可能時間更短。其實各種語言的語法和常用函數都差別不大,有很多相通的地方。如果您在學習一種編程語言的時候,拿一些真正的項目任務作為實踐,效果更佳,實踐遠勝於理論。

我們在掌握了一門編程語言之後,又會向兩個方向發展:一個方向是向上延伸,從事系統框架結構的探索;另一方向是向下延伸,從事系統底層方面的研究,我大體畫了一下這個學習演變過程的示意圖。

 

 

 

注:雖然我的形象一直用著“高高手”,但我只是個菜鳥,如有雷同,純屬巧合,歡迎善意拍磚。

 

php的語法非常簡單,正是它的簡單性,使它成為了當前互聯網第一編程語言。你不需要具備很多的知識就能上手,比如:你學習C語言,就必須非常了解各個變量如何定義,指針如何操作,內存如何創建銷毀等等。再比如:你學習Java語言,就必須具有面向對象(OO)的基礎,就必須清楚是什麼時候需要封裝,什麼時候需要繼承,什麼時候需要多態,要做項目,怎麼還得懂點SSH。Php的大部分使用者可能根本就沒這麼多講究,有的人喜歡面向過程,那你就用面向過程的方式來寫代碼;有的人喜歡面向對象,那你就用面向對象的方式寫代碼。Php的產生緣於互聯網,目前也是互聯網Web2.0第一編程語言。滿足用戶需求永遠是第一位的,可維護性暫且可以放在第二位。我們通常說Web應用永遠是β版的,計劃遠沒有變化快。

我們公司裡有很多phper,我曾經問過他們:“php程序到底是如何被執行的?”,多數人似乎很難說得清楚。這種情況,其實並不奇怪,我曾經拿類似的問題問過Javaer,Javaer的回答也是如此。有的同學會問:“研究這樣的問題有沒有實際意義呢?”我說:“有!”。理解系統的底層,有助於你寫出高效健壯的代碼,你會更清楚程序的代碼到底該怎麼去寫。另外,如果你有志去做php擴展,那就更不必說,責無旁貸。

要回答以上問題,我覺得最好的辦法是閱讀一下php的源碼,從“根”上解決。近來我找了點時間,粗讀了一遍,願意與各位共享。

關於php的底層工作原理,一定繞不開webserver,象apache,lighttpd,nginx,iis等。我這裡就選擇apache為例吧。以下內容將結合apache的源碼、工作原理和擴展來逐步切入php的解析過程。


 

二、Apache運行機制剖析

l         B/S交互過程

浏覽器(Browser)和服務器(Web Server)的交互過程:

 

 

 

1、  浏覽器向服務器發出HTTP請求(Request)。

2、  服務器收到浏覽器的請求數據,經過分析處理,向浏覽器輸出響應數據(Response)。

3、  浏覽器收到服務器的響應數據,經過分析處理,將最終結果顯示在浏覽器中。

 下圖是一份浏覽器請求數據和服務器響應數據的快照:

 

 

關於浏覽器和服務器數據交互過程非常簡單,很容易理解。我想從事Web開發的人員都很清楚,在此不再贅述,僅供參考。

 

l         Apache概述

Apache是目前世界上使用最為廣泛的一種Web Server,它以跨平台、高效和穩定而聞名。按照去年官方統計的數據,Apache服務器的裝機量占該市場60%以上的份額。尤其是在X(Unix/Linux)平台上,Apache是最常見的選擇。其它的Web Server產品,比如IIS,只能運行在Windows平台上,是基於微軟.Net架構技術的不二選擇。

Apache並不是沒有缺點,它最為诟病的一點就是變得越來越重,被普遍認為是重量級的WebServer。所以,近年來又湧現出了很多輕量級的替代產品,比如lighttpd,nginx等等,這些WebServer的優點是運行效率很高,但缺點也很明顯,成熟度往往要低於Apache,通常只能用於某些特定場合,。

 

l         Apache組件邏輯圖

Apache是基於模塊化設計的,總體上看起來代碼的可讀性高於php的代碼,它的核心代碼並不多,大多數的功能都被分散到各個模塊中,各個模塊在系統啟動的時候按需載入。你如果想要閱讀Apache的源代碼,建議你直接從main.c文件讀起,系統最主要的處理邏輯都包含在裡面。MPM(Multi -Processing Modules,多重處理模塊)是Apache的核心組件之一,Apache通過MPM來使用操作系統的資源,對進程和線程池進行管理。Apache為了能夠獲得最好的運行性能,針對不同的平台(Unix/Linux、Window)做了優化,為不同的平台提供了不同的MPM,用戶可以根據實際情況進行選擇,其中最常使用的MPM有prefork和worker兩種。至於您的服務器正以哪種方式運行,取決於安裝Apache過程中指定的MPM編譯參數,在X系統上默認的編譯參數為prefork。由於大多數的Unix都不支持真正的線程,所以采用了預派生子進程(prefork)方式,象Windows或者Solaris這些支持線程的平台,基於多進程多線程混合的worker模式是一種不錯的選擇。對此感興趣的同學可以閱讀有關資料,此處不再多講。Apache中還有一個重要的組件就是APR(Apache portable Runtime Library),即Apache可移植運行庫,它是一個對操作系統調用的抽象庫,用來實現Apache內部組件對操作系統的使用,提高系統的可移植性。Apache對於php的解析,就是通過眾多Module中的php Module來完成的。

 

 

Apache的邏輯構成以及與操作系統的關系

 

l         Apache的生命周期

這一節的內容會與php模塊的載入有關,您可以略微關注一下。以下是Apache的生命周期(prefork模式)示意圖。

 

 

   

這一篇多寫一點內容,主要是今天終於有時間了。最近工作一直比較忙,公司裡一大攤子事情需要處理,哥們首先得賣身混飯吃,其次才能在閒得蛋疼的時候寫一點。閒話少敘,書接上回:

 

l         Apache的生命周期

這一節的內容將會闡述php模塊的載入過程,請參考Apache的生命周期示意圖(prefork模式下)。

 

Apache的運行分為啟動階段和運行階段。

 

1.         啟動階段

在啟動階段,Apache主要進行配置文件解析(例如http.conf以及Include指令設定的配置文件等)、模塊加載(例如mod_php.so,mod_perl.so等)和系統資源初始化(例如日志文件、共享內存段等)工作。

在這個階段,Apache為了獲得系統資源最大的使用權限,將以特權用戶root(X系統)或超級管理員administrator(Windows系統)完成啟動。

 

Apache和“php處理機”的裝配過程就是在這個階段完成的。

“php處理機”就是負責解釋和執行你的php代碼的系統模塊。這個名字是我特意創造的,目的是為了幫助你理解本節的內容,後面的章節還會給出更專業的名稱。

 

你單獨做過php的安裝配置嗎?

如果你做過類似的工作,下面的內容很容易理解;如果你沒有做過,可以嘗試安裝一下,有助於加深你的理解。不過,我的文章向來深入淺出,我會盡量把這個過程講得更淺顯一些。其實php的安裝非常簡單,如果你很感興趣的話,可以到網上隨便搜一篇安裝指南,按步驟照做就可以了。

把php最終集成到Apache系統中,還需要對Apache進行一些必要的設置。這裡,我們就以php的mod_php5 SAPI運行模式為例進行講解,至於SAPI這個概念後面我們還會詳細講解。

假定我們安裝的版本是Apache2 和 Php5,那麼需要編輯Apache的主配置文件http.conf,在其中加入下面的幾行內容:

Unix/Linux環境下

LoadModule php5_module modules/mod_php5.so

AddType application/x-httpd-php .php

注:其中modules/mod_php5.so 是X系統環境下mod_php5.so文件的安裝位置。

 

Windows環境下:

LoadModule php5_module d:/php/php5apache2.dll

AddType application/x-httpd-php .php

注:其中d:/php/php5apache2.dll 是在Windows環境下php5apache2.dll文件的安裝位置。

這兩項配置就是告訴Apache Server,以後收到的Url用戶請求,凡是以php作為後綴,就需要調用php5_module模塊(mod_php5.so/ php5apache2.dll)進行處理。

 

這個過程可以參考以下的示意圖:

 

 

 

Apache啟動階段的源碼包含在server/main.c中,我整理了一下源碼中的對應關系:

 

 

 

 

不熟悉unix/linux的同學可能會問so文件(mod_php5.so)是個什麼樣的文件?

unix/linux下,so後綴文件是一個DSO文件,DSO與windows系統下的dll是等價概念,都是把一堆函數封裝在一個二進制文件中。調用它們的進程把它們裝入內存後,會將其映射到自己的地址空間。

DSO全稱為Dynamic Shared Object,即動態共享對象。DLL全稱為Dynamic Link Library 即動態鏈接庫。

Apache 服務器的體系結構的最大特點,就是高度模塊化。如果你為了追求處理效率,可以把這些dso模塊在apache編譯的時候靜態鏈入,這樣會提高Apache 5%左右的處理性能。

   

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved