搜尋
首頁後端開發PHP問題php底層運作原理詳細介紹

php底層運作原理詳細介紹

Sep 02, 2019 pm 01:13 PM
php底層運作原理

php底層運作原理詳細介紹

PHP是一種適用於web開發的動態語言。具體點說,就是一個用C語言實作包含大量元件模組的軟體框架。是一個強大的UI框架。

簡言之;PHP動態語言執行過程:拿到一段程式碼後,經過詞法解析、語法解析等階段後,原始程式會被翻譯成一個個指令(opcodes),然後ZEND虛擬機器順次執行這些指令完成操作。 PHP本身是用C來實現的,因此最後呼叫的也是C的函數,實際上,我們可以把PHP看做一個C開發的軟體。

一、php的設計概念及特點

1、多進程模型:由於PHP是多進程模型,不同請求間互不干涉,這樣保證了一個請求掛掉不會對全碟服務造成影響,目前PHP也早支援多執行緒模型。

2、弱型別語言:和C/C 、JAVA、C#等語言不同,PHP是一種弱型別的語言。一個變數的類型並不是一開始就確定不變的,運行中才會確定並可能發生隱式或顯示的類型轉換,這種機制的靈活性在web開發中非常方便、高效,具體會在後面PHP變數中詳述。

3、引擎(Zend) 元件(ext)的模式降低內部耦合。

4、中間層(sapi )Sapi全名為Server Application Programming Interface 隔絕web server和PHP。

5、文法簡單靈活,沒有太多規範。缺點導致風格混雜。

二、php的四層體系

PHP的核心架構如下圖:

php底層運作原理詳細介紹

PHP從下到上是4層系統:

1、Zend引擎:Zend整體用純C實現,是PHP的核心部分,他將PHP程式碼翻譯(詞法、語法解析等一系列編譯過程)為可執行opcode的處理並實現對應的處理方法、實作了基本的資料結構(如:hashtable、OO)、記憶體分配機制及管理、提供了對應的api方法供外部調用,是一切的核心,所有的外圍功能均圍繞著Zend實作。

2、Extensions:圍繞著Zend引擎,extensions透過元件式的方式提供各種基礎服務,我們常見的各種內建函數(array系列)、標準函式庫等都是透過extension來實現,用戶也可以根據需要實現自己的extension的典型應用)。

3、Sapi:Sapi全名為Server Application Programming Interface,也就是服務端應用程式接口,Sapi透過一系列鉤子函數,使得PHP可以和外圍交互數據,這是PHP非常優雅和成功的設計,透過sapi成功的將PHP本身和上層應用解耦隔離,PHP可以不再考慮如何針對不同應用進行相容,而應用程式本身也可以針對自己的特點實現不同的處理方式。

4、上層應用:這就是我們平時編寫的P​​HP程序,透過不同的spai方式得到各種各樣的應用模式,如何透過webserver實現web應用、在命令列下已腳本方式運行等等。

我們需要:性能優異的引擎(Zend) 合適的車輪(Ext) 正確的跑道(Sapi)。

三、Sapi

Sapi透過一系列的接口,使得外部應用可以和PHP交換資料並且可以根據不同應用特徵實現特定的處理方法,我們常見一些sapi有:

1、apache2handler:這是以apache作為webserver,採用mod_PHP模式運行時的處理方式,也是現在應用最廣泛的一種。

2、cgi:這是webserver和PHP直接的另一種互動方式,也就是大名鼎鼎的fastcgi協議,在最近fastcgi PHP得到越來越多的應用,也是異步webserver所唯一支持的方式;典型應用nginx伺服器;fastcgi 說白點就是php的一個擴充。

    Web Server啟動時載入FastCGI進程管理器(IIS ISAPI或Apache Module)

    FastCGI進程管理器本身初始化,啟動多個CGI解釋器進程(可見多個php-cgi )並等待來自Web Server的連線。

    當客戶端要求到達Web Server時,FastCGI進程管理器選擇並連接到一個CGI解釋器。 Web server將CGI環境變數和標準輸入傳送到FastCGI子進程php-cgi。

    FastCGI子進程完成處理後將標準輸出和錯誤訊息從相同連線返回Web Server。當FastCGI子程序關閉連線時,請求便告處理完成。 FastCGI子進程接著等待並處理來自FastCGI進程管理器(運行在Web Server中)的下一個連線。在CGI模式中,php-cgi在此便退出了。

    在上述情況中,你可以想像CGI通常有多慢。每一個Web請求PHP都必須重新解析php.ini、重新載入全部擴充並重初始化全部資料結構。使用FastCGI,所有這些都只在進程啟動時發生一次。一個額外的好處是,持續資料庫連線(Persistent database connection)可以運作。

php底層運作原理詳細介紹

php底層運作原理詳細介紹

3、cli:命令列呼叫的應用模式

命令列介面(英文:command-line interface,縮寫: CLI)是在圖形使用者介面普及之前使用最廣泛的使用者介面,它通常不支援滑鼠,使用者透過鍵盤輸入指令,電腦接收到指令後,予以執行。也有人稱之為字元使用者介面(CUI)。
通常認為,命令列介面(CLI)沒有圖形使用者介面(GUI)那麼方便使用者操作。因為,命令列介面的軟體通常需要使用者記憶操作的命令,但是,由於其本身的特點,命令列介面要較圖形使用者介面節約電腦系統的資源。在熟記命令的前提下,使用命令列介面往往要較使用圖形使用者介面的操作速度要快。所以,圖形使用者介面的作業系統中,都保留著可選的命令列介面。

四、php的執行流程

php底層運作原理詳細介紹

#PHP動態語言執行過程:拿到一段程式碼後,經過詞法解析、語法解析等階段後,原始程式會被翻譯成一個個指令(opcodes),然後ZEND虛擬機器順次執行這些指令完成操作。 PHP本身是用C來實現的,因此最後呼叫的也是C的函數,實際上,我們可以把PHP看做一個C開發的軟體。

PHP的執行的核心是翻譯出來的一條一條指令,也是opcode。

Opcode是PHP程式執行的最基本單位。

在電腦科學領域中,操作碼(Operation Code, OPCode)被用來描述機器語言指令中,指定要執行某種操作的那部分機器碼,構成OPCode的指令格式和規範由處理器的指令規格指定。

一個opcode由兩個參數(op1,op2)、傳回值和處理函數組成。 PHP程式最終被翻譯為一組opcode處理函數的順序執行。

常見的幾個處理函數:

ZEND_ASSIGN_SPEC_CV_CV_HANDLER : 变量分配 ($a=$b)
ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER:函数调用
ZEND_CONCAT_SPEC_CV_CV_HANDLER:字符串拼接 $a.$b
ZEND_ADD_SPEC_CV_CONST_HANDLER: 加法运算 $a+2
ZEND_IS_EQUAL_SPEC_CV_CONST:判断相等 $a==1
ZEND_IS_IDENTICAL_SPEC_CV_CONST:判断相等 $a===1

#五、HashTable-核心資料結構

HashTable是Zend的核心資料結構,在PHP裡面幾乎並用來實現所有常見功能,我們所知道的PHP陣列即是其典型應用,此外,在zend內部,如函數符號表、全域變數等也都是基於hash table具有以下特點:

1、支援典型的key->value查詢

2、可以當做陣列使用

3、新增、刪除節點是O(1)複雜度

4.key支援混合型別:同時存在關聯數組合索引數組

5、Value支援混合型別:array("string",2332)

6、支援線性遍歷:如foreach

Zend hash table實現了典型的hash表散列結構,同時透過附加一個雙向鍊錶,提供了正向、反向遍歷數組的功能。其架構如下圖:

php底層運作原理詳細介紹

可以看到:在hash table中既有key->value形式的雜湊結構,也有雙向鍊錶模式,使得它能夠非常方便的支援快速查找和線性遍歷。

1、雜湊結構:Zend的雜湊結構是典型的hash表模型,透過鍊錶的方式來解決衝突。需要注意的是zend的hash table是一個自增長的資料結構,當hash表數目滿了之後,其本身會動態以2倍的方式擴容並重新元素位置。初始大小均為8。另外,在進行 key->value快速尋找時候,zend本身也做了一些優化,透過空間換時間的方式加快速度。例如在每個元素中都會用一個變數 nKeyLength來標識key的長度以作快速判定。

2、雙向鍊錶:Zend hash table透過一個鍊錶結構,實現了元素的線性遍歷。理論上,做遍歷使用單向鍊錶就夠了,之所以使用雙向鍊錶,主要目的是為了快速刪除,避免遍歷。 Zend hash table是一種複合型的結構,作為數組使用時,即支援常見的關聯數組也能夠作為順序索引數字來使用,甚至允許2者的混合。 PHP關聯數組:關聯數組是典型的hash_table應用程式。一次查詢過程經過以下幾步(從程式碼可以看出,這是一個常見的hash查詢過程並增加一些快速判定加速查找。):

getKeyHashValue h;
index = n & nTableMask;
Bucket *p = arBucket[index];
while (p) {
       if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
              RETURN p->data;   
        }
        p=p->next;
}
RETURN FALTURE;

4、PHP索引数组:索引数组就是我们常见的数组,通过下标访问。例如 $arr[0],Zend HashTable内部进行了归一化处理,对于index类型key同样分配了hash值和nKeyLength(为0)。内部成员变量 nNextFreeElement就是当前分配到的最大id,每次push后自动加一。正是这种归一化处理,PHP才能够实现关联和非关联的混合。由于 push操作的特殊性,索引key在PHP数组中先后顺序并不是通过下标大小来决定,而是由push的先后决定。例如 $arr[1] = 2; $arr[2] = 3;对于double类型的key,Zend HashTable会将他当做索引key处理。

六、Hash Table变量

PHP是一门弱类型语言,本身不严格区分变量的类型。PHP在变量申明的时候不需要指定类型。

PHP在程序运行期间可能进行变量类型的隐示转换。 和其他强类型语言一样,程序中也可以进行显示的类型转换。

PHP变量可以分为简单类型(int、string、bool)、集合类型(array resource object)和常量(const)。以上所有的变量在底层都是同一种结构 zval。

Zval主要由三部分组成:

type:指定了变量所述的类型(整数、字符串、数组等)

refcount&is_ref:用来实现引用计数(后面具体介绍)

value:核心部分,存储了变量的实际数据

Zvalue是用来保存一个变量的实际数据。因为要存储多种类型,所以zvalue是一个union,也由此实现了弱类型。

引用计数在内存回收、字符串操作等地方使用非常广泛。PHP中的变量就是引用计数的典型应用。Zval的引用计数通过成员变量is_ref和ref_count实现,通过引用计数,多个变量可以共享同一份数据。避免频繁拷贝带来的大量消耗。在进行赋值操作时,zend将变量指向相同的zval同时ref_count++,在unset操作时,对应的ref_count-1。只有ref_count减为0时才会真正执行销毁操作。如果是引用赋值,则zend会修改is_ref为1。

PHP变量通过引用计数实现变量共享数据,那如果改变其中一个变量值呢?当试图写入一个变量时,Zend若发现该变量指向的zval被多个变量共 享,则为其复制一份ref_count为1的zval,并递减原zval的refcount,这个过程称为“zval分离”。可见,只有在有写操作发生时 zend才进行拷贝操作,因此也叫copy-on-write(写时拷贝)对于引用型变量,其要求和非引用型相反,引用赋值的变量间必须是捆绑的,修改一个变量就修改了所有捆绑变量。整数、浮点数是PHP中的基础类型之一,也是一个简单型变量。对于整数和浮点数,在zvalue中直接存储对应的值。其类型分别是long和double。

从zvalue结构中可以看出,对于整数类型,和c等强类型语言不同,PHP是不区分int、unsigned int、long、long long等类型的,对它来说,整数只有一种类型也就是long。由此,可以看出,在PHP里面,整数的取值范围是由编译器位数来决定而不是固定不变的。

对于浮点数,类似整数,它也不区分float和double而是统一只有double一种类型。在PHP中,如果整数范围越界了怎么办?这种情况下会自动转换为double类型,这个一定要小心,很多trick都是由此产生。

和整数一样,字符变量也是PHP中的基础类型和简单型变量。通过zvalue结构可以看出,在PHP中,字符串是由由指向实际数据的指针和长度结 构体组成,这点和c++中的string比较类似。由于通过一个实际变量表示长度,和c不同,它的字符串可以是2进制数据(包含\0),同时在PHP中, 求字符串长度strlen是O(1)操作。在新增、修改、追加字符串操作时,PHP都会重新分配内存生成新的字符串。最后,出于安全考虑,PHP在生成一个字符串时末尾仍然会添加\0。

常见的字符串拼接方式及速度比较:假设有如下4个变量:$strA=‘123’; $strB = ‘456’; $intA=123; intB=456;

现在对如下的几种字符串拼接方式做一个比较和说明:

$res = $strA.$strB和$res = “$strA$strB”
这种情况下,zend会重新malloc一块内存并进行相应处理,其速度一般
$strA = $strA.$strB
这种是速度最快的,zend会在当前strA基础上直接relloc,避免重复拷贝
$res = $intA.$intB
这种速度较慢,因为需要做隐式的格式转换,实际编写程序中也应该注意尽量避免
$strA = sprintf (“%s%s”,$strA.$strB);
这会是最慢的一种方式,因为sprintf在PHP中并不是一个语言结构,本身对于格式识别和处理就需要耗费比较多时间,另外本身机制

也是malloc内存。不过sprintf的方式最具可读性,实际中可以根据具体情况灵活选择。

PHP的数组通过Zend HashTable来天然实现。foreach操作如何实现?对一个数组的foreach就是通过遍历hashtable中的双向链表完成。对于索引数组,通过foreach遍 历效率比for高很多,省去了key->value的查找。count操作直接调用 HashTable->NumOfElements,O(1)操作。对于’123’这样的字符串,zend会转换为其整数形 式。$arr[‘123’]和$arr[123]是等价的

資源類型變數是PHP中最複雜的一種變量,也是一種複合型結構。 PHP的zval可以表示廣泛的資料類型,但是對於自訂的資料類型卻很難充分描述。由於沒有有效的方式描繪這些複合結構,因此也沒有辦法對它們使用傳統的操作符。要解決這個問題,只需要透過一個本質上任意的標識符(label)來引用指針,這種方式稱為資源。

在zval中,對於resource,lval作為指標來使用,直接指向資源所在的位址。 Resource可以是任意的複合結構,我們熟悉的mysqli、fsock、memcached等都是資源。

如何使用資源:

註冊:對於一個自訂的資料類型,要想將它作為資源。首先需要進行註冊,zend會為它指派全域唯一標示。

取得一個資源變數:對於資源,zend維護了一個id->實際資料的hash_tale。對於一個resource,在zval中只記錄了它的id。 fetch的時候透過id在hash_table中找到具體的值返回。

資源銷毀:資源的資料型別是多種多樣的。 Zend本身沒有辦法銷毀它。因此需要使用者在註冊資源的時候提供銷毀函數。
當unset資源時,zend呼叫對應的函數完成析構。同時從全域資源表中刪除它。

資源可以長期駐留,不只是在所有引用它的變數超出作用域之後,甚至是在一個請求結束了並且新的請求產生之後。這些資源稱為持久資源,因為它們貫通 SAPI的整個生命週期持續存在,除非刻意銷毀。很多情況下,持久化資源可以在一定程度上提高效能。例如我們常見的mysql_pconnect ,持久化資源透過pemalloc分配內存,這樣在請求結束的時候不會釋放。對zend來說,對兩者本身並不區分。

PHP中的局部變數和全域變數是如何實現的?對於一個請求,任意時刻PHP都可以看到兩個符號表(symbol_table和 active_symbol_table),其中前者用來維護全域變數。後者是指針,指向目前活動的變數符號表,當程式進入某個函數時,zend 就會為它指派一個符號表x同時將active_symbol_table指向a。透過這樣的方式實現全域、局部變數的區分。

取得變數值:PHP的符號表是透過hash_table實現的,對於每個變數都分配唯一標識,取得的時候根據標識從表中找到對應zval返回。

函數中使用全域變數:在函數中,我們可以透過明確申明global來使用全域變數。在active_symbol_table中建立symbol_table中同名變數的引用,如果symbol_table中沒有同名變數則會先建立。

推薦php中文網影片教學:PHP影片教學

#

以上是php底層運作原理詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
酸與基本數據庫:差異和何時使用。酸與基本數據庫:差異和何時使用。Mar 26, 2025 pm 04:19 PM

本文比較了酸和基本數據庫模型,詳細介紹了它們的特徵和適當的用例。酸優先確定數據完整性和一致性,適合財務和電子商務應用程序,而基礎則側重於可用性和

PHP安全文件上傳:防止與文件相關的漏洞。PHP安全文件上傳:防止與文件相關的漏洞。Mar 26, 2025 pm 04:18 PM

本文討論了確保PHP文件上傳的確保,以防止諸如代碼注入之類的漏洞。它專注於文件類型驗證,安全存儲和錯誤處理以增強應用程序安全性。

PHP輸入驗證:最佳實踐。PHP輸入驗證:最佳實踐。Mar 26, 2025 pm 04:17 PM

文章討論了PHP輸入驗證以增強安全性的最佳實踐,重點是使用內置功能,白名單方法和服務器端驗證等技術。

PHP API率限制:實施策略。PHP API率限制:實施策略。Mar 26, 2025 pm 04:16 PM

本文討論了在PHP中實施API速率限制的策略,包括諸如令牌桶和漏水桶等算法,以及使用Symfony/Rate-limimiter之類的庫。它還涵蓋監視,動態調整速率限制和手

php密碼哈希:password_hash和password_verify。php密碼哈希:password_hash和password_verify。Mar 26, 2025 pm 04:15 PM

本文討論了使用password_hash和pyspasswify在PHP中使用密碼的好處。主要論點是,這些功能通過自動鹽,強大的哈希算法和SECH來增強密碼保護

OWASP前10 php:描述並減輕常見漏洞。OWASP前10 php:描述並減輕常見漏洞。Mar 26, 2025 pm 04:13 PM

本文討論了OWASP在PHP和緩解策略中的十大漏洞。關鍵問題包括注射,驗證損壞和XSS,並提供用於監視和保護PHP應用程序的推薦工具。

PHP XSS預防:如何預防XSS。PHP XSS預防:如何預防XSS。Mar 26, 2025 pm 04:12 PM

本文討論了防止PHP中XSS攻擊的策略,專注於輸入消毒,輸出編碼以及使用安全增強的庫和框架。

PHP接口與抽像類:何時使用。PHP接口與抽像類:何時使用。Mar 26, 2025 pm 04:11 PM

本文討論了PHP中接口和抽像類的使用,重點是何時使用。界面定義了無實施的合同,適用於無關類和多重繼承。摘要類提供常見功能

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。