1、PHP是什么?
PHP 指的是我們從外面看到的一套完整的系統(tǒng)。這聽起來有點(diǎn)糊涂,但其實(shí)并不復(fù)雜(PHP4 內(nèi)部結(jié)構(gòu)圖)。從功能上來分:我們可以分為三部分:
1、 解釋器部分(Zend 以引擎),負(fù)責(zé)對(duì)輸入代碼的分析、翻譯和執(zhí)行;
2、 功能性部分(PHP功能函數(shù)以及擴(kuò)展),負(fù)責(zé)具體實(shí)現(xiàn)語(yǔ)言的各種功能(比如它的函數(shù)等等);
3、 接口部分(SAPI),負(fù)責(zé)同 WEB 服務(wù)器的會(huì)話等功能。 Zend包括了第一部分的全部和第二部分的局部,PHP內(nèi)核 包括了第二部分的局部和第三部分的全部。他們合起來稱之為 PHP 包。Zend 構(gòu)成了語(yǔ)言的核心,同時(shí)也包含了一些最基本的 PHP 預(yù)定義函數(shù)的實(shí)現(xiàn)。PHP 包(內(nèi)核)則包含了所有創(chuàng)造出語(yǔ)言本身各種顯著特性的模塊。
(PHP 內(nèi)部結(jié)構(gòu)圖)
從內(nèi)容模塊上來分:我們可以分為四層體系結(jié)構(gòu):
1)Zend引擎:Zend整體用純c實(shí)現(xiàn),是php的內(nèi)核部分,它將php代碼翻譯(詞法、語(yǔ)法解析等一系列編譯過程)為可執(zhí)行opcode的處理并實(shí)現(xiàn)相應(yīng)的處理方法、實(shí)現(xiàn)了基本的數(shù)據(jù)結(jié)構(gòu)(如hashtable、oo)、內(nèi)存分配及管理、提供了相應(yīng)的api方法供外部調(diào)用,是一切的核心,所有的外圍功能均圍繞zend實(shí)現(xiàn)。
2)Extensions擴(kuò)展:圍繞著zend引擎,extensions通過組件式的方式提供各種基礎(chǔ)服務(wù),我們常見的各種內(nèi)置函數(shù)(如array系列)、標(biāo)準(zhǔn)庫(kù)等都是通過extension來實(shí)現(xiàn),用戶也可以根據(jù)需要實(shí)現(xiàn)自己的extension以達(dá)到功能擴(kuò)展、性能優(yōu)化等目的(如貼吧正在使用的php中間層、富文本解析就是extension的典型應(yīng)用)。
3)Sapi :Sapi全稱是Server Application Programming Interface,也就是服務(wù)端應(yīng)用編程接口,sapi通過一系列鉤子函數(shù),使得php可以和外圍交互數(shù)據(jù),這是php非常優(yōu)雅和成功的一個(gè)設(shè)計(jì),通過sapi成功的將php本身和上層應(yīng)用解耦隔離,php可以不再考慮如何針對(duì)不同應(yīng)用進(jìn)行兼容,而應(yīng)用本身也可以針對(duì)自己的特點(diǎn)實(shí)現(xiàn)不同的處理方式。
4)上層應(yīng)用: 這就是我們平時(shí)編寫的php程序,通過不同的sapi方式得到各種各樣的應(yīng)用模式,如通過webserver實(shí)現(xiàn)web應(yīng)用、在命令行下以腳本方式運(yùn)行等等。
(php結(jié)構(gòu) )
其架構(gòu)思想:引擎(Zend)+擴(kuò)展(ext)的模式:降低內(nèi)部耦合
中間層(sapi):web server和php的通信接口, 隔絕web server和php。
如果php是一輛車,那么
車的框架就是php本身,即是我們外面看到一套完整系統(tǒng)。
Zend是車的引擎(發(fā)動(dòng)機(jī))
Ext下面的各種組件就是車的輪子
Sapi可以看做是公路,車可以跑在不同類型的公路上
而一次php程序的執(zhí)行就是汽車跑在公路上。
因此,我們需要:性能優(yōu)異的引擎+合適的車輪+正確的跑道
2、php生命周期
查看:深入理解php底層:php生命周期 :http://blog.csdn.net/hguisu/article/details/7377520
3 、sapi
如前所述,sapi通過通過一系列的接口,使得外部應(yīng)用可以和php交換數(shù)據(jù)并可以根據(jù)不同應(yīng)用特點(diǎn)實(shí)現(xiàn)特定的處理方法,我們常見的一些sapi有:
1) 、apache2handler :這是以apache作為webserver,采用mod_php模式運(yùn)行時(shí)候的處理方式,也是現(xiàn)在應(yīng)用最廣泛的一種。
2)、cgi :這是webserver和php直接的另一種交互方式,也就是大名鼎鼎的fastcgi協(xié)議,在最近今年fastcgi+php得到越來越多的應(yīng)用,也是異步webserver所唯一支持的方式。
3)、cli :命令行調(diào)用的應(yīng)用模式
如圖:Sapi的簡(jiǎn)單示意圖
Sapi的定義及主要接口函數(shù):
struct _sapi_module_struct { char *name; // 名字標(biāo)識(shí) char *pretty_name; // 更好理解的名字 int (*startup)(struct _sapi_module_struct *sapi_module); // 啟動(dòng)函數(shù) int (*shutdown)(struct _sapi_module_struct *sapi_module); // 關(guān)閉方法 int (*activate)(TSRMLS_D); //激活 int (*deactivate)(TSRMLS_D); // 停用 int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC); // 沒有緩存的寫操作(unbuffered write) void (*flush)(void *server_context); // flush struct stat *(*get_stat)(TSRMLS_D); // get uid char *(*getenv)(char *name, size_t name_len TSRMLS_DC); // getenv void (*sapi_error)(int type, const char *error_msg, ...); /* error handler */ int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC); /* header handler */ /* send headers handler */ int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC); void (*send_header)(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC); /* send header handler */ int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC); /* read POST data */ char *(*read_cookies)(TSRMLS_D); /* read Cookies */ /* register server variables */ void (*register_server_variables)(zval *track_vars_array TSRMLS_DC); void (*log_message)(char *message); /* Log message */ time_t (*get_request_time)(TSRMLS_D); /* Request Time */ void (*terminate_process)(TSRMLS_D); /* Child Terminate */ char *php_ini_path_override; //覆蓋ini路徑 ... ...};
這里介紹一下其中一些主要函數(shù)
· startup:php被調(diào)用時(shí)初始化操作,比如cgi模式,在startup的時(shí)候會(huì)加載所有的extension并執(zhí)行模塊初始化工作。
· shutdown:php關(guān)閉時(shí)收尾工作
· activate:請(qǐng)求初始化
· dectivate:請(qǐng)求結(jié)束時(shí)收尾工作
· ub_write:指定數(shù)據(jù)輸出方式,比如apache2handler方式,由于php作為apache的一個(gè)so存在,因此其輸出也就是調(diào) 用apache的ap_write函數(shù),而在cgi模式下,會(huì)系統(tǒng)調(diào)用write。
· sapi_error:錯(cuò)誤處理函數(shù)
· read_post:讀取post數(shù)據(jù)
· register_server_variables:往$_SERVER中注冊(cè)環(huán)境變量這個(gè)一般根據(jù)不同協(xié)議標(biāo)準(zhǔn)注冊(cè)注冊(cè)的變量。
在php源碼中,sapi實(shí)現(xiàn)了很多接口:如下圖:
4、php腳本的執(zhí)行
SAPI處于PHP架構(gòu)的上層,而真正的腳本執(zhí)行是有Zend引擎來完成。
目前語(yǔ)言分為兩類:
第一類:編譯型語(yǔ)言.如c/c++ java之類,他們的共性是運(yùn)行之前必須對(duì)源代碼進(jìn)行編譯,然后運(yùn)行編譯后的目標(biāo)文件。
第二類語(yǔ)言:解釋型語(yǔ)言:如PHP,Ruby,Python。他們需要解釋器來執(zhí)行這些源代碼。實(shí)際上這些語(yǔ)言還是要經(jīng)過編譯環(huán)節(jié)的。只不過他們?cè)谶\(yùn)行的時(shí)候進(jìn)行編譯,為了效率,并不是每次執(zhí)行的時(shí)候都會(huì)重新編譯,比如PHP的各種opcode緩存擴(kuò)展(如APC Xcache等)。
說明:PHP從2000年發(fā)布的PHP4開始就不是解釋性語(yǔ)言。當(dāng)一個(gè)PHP腳本被執(zhí)行的時(shí)候,首先PHP源代碼由Zend引擎編譯成名為Zend opcodes的機(jī)器代碼。這些代碼保存在RAM中。然后執(zhí)行opcodes運(yùn)行真正的腳本。因此,PHP實(shí)際上和Java,C#等語(yǔ)言一樣是編譯語(yǔ)言。否則,它的執(zhí)行會(huì)很慢。
我們來看PHP腳本是怎么被執(zhí)行的。如hello.php:
?php$str = "Hello world!\n";echo $str;
命令行執(zhí)行:php hello.php
輸出結(jié)果顯然是:Hello world!
但是執(zhí)行腳本的時(shí)候,PHP/Zend做了什么呢?
4.1、程序的執(zhí)行:
1)傳遞給php程序需要的執(zhí)行文件hello.php,php程序完成基本的準(zhǔn)備工作后啟動(dòng)PHP及Zend引擎,加載注冊(cè)的擴(kuò)展模塊。
2) 初始化完后讀取腳本文件,Zend引擎對(duì)腳本進(jìn)行此詞法分析,語(yǔ)法分析,然后有Zend引擎編譯成opcode碼,最后執(zhí)行 opcode碼。
php代碼的執(zhí)行過程如下圖:
php實(shí)現(xiàn)了一個(gè)典型的動(dòng)態(tài)語(yǔ)言執(zhí)行過程:拿到一段代碼后,經(jīng)過詞法解析、語(yǔ)法解析等階段后,源程序會(huì)被翻譯成一個(gè)個(gè)指令(opcodes),然后ZEND虛擬機(jī)順次執(zhí)行這些指令完成操作。PHP本身是用c實(shí)現(xiàn)的,因此最終調(diào)用的也都是c的函數(shù),實(shí)際上,我們可以把php看做是一個(gè)c開發(fā)的軟件。
通過上面描述不難看出,php的執(zhí)行的核心是翻譯出來的一條一條指令,也即opcode.
4.2、詞法分析和語(yǔ)法分析
解釋器一般包括兩部分:
1)、 讀取源程序,并處理語(yǔ)言結(jié)構(gòu)
2)、處于語(yǔ)言結(jié)構(gòu)并生成目標(biāo)程序
而Lex和Yacc可以解決第一個(gè)問題。很多編程都有Lex/Yacc作為語(yǔ)言的詞法語(yǔ)法分析生成器,比如PHP,Python、Ruby已經(jīng)MySql的sql語(yǔ)言。
Lex生成詞法分析器。
Yacc語(yǔ)法分析生成器
4. 3、opcode
PHP 構(gòu)建在Zend虛擬機(jī)(Zend VM)之上的,PHP的opcode就是ZEND 虛擬機(jī)中的指令,即Opcode是php程序執(zhí)行的最基本單位。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
您可能感興趣的文章:- 詳解PHP的執(zhí)行原理和流程
- 通過代碼實(shí)例解析PHP session工作原理
- PHP數(shù)組實(shí)際占用內(nèi)存大小原理解析
- PHP超全局變量實(shí)現(xiàn)原理及代碼解析
- PHP數(shù)組Key強(qiáng)制類型轉(zhuǎn)換實(shí)現(xiàn)原理解析
- JS PHP字符串截取函數(shù)實(shí)現(xiàn)原理解析
- PHP unset函數(shù)原理及使用方法解析
- PHP 命名空間原理與用法詳解
- 如何理解PHP程序執(zhí)行的過程原理