PHP7語言的執行原理(PHP7源碼分析)
我們常用的高階語言有很多種,比較出名的有CC 、Python、 PHP、Go、Pascal等。而這些語言依運行的方式不同,大體分為兩種:編譯型語言和解釋型語言。
其中,編譯型語言包括CC 、Pascal、Go等。這裡說的編譯是指在應用程式原始程式執行之前,就將程式原始碼「翻譯」成組合語言,然後進一步根據軟硬體環境編譯成目標檔。一般我們稱完成編譯工作的工具叫編譯器。而解釋型語言,在程式執行時才被「翻譯」為機器語言。但是執行一次「翻譯」一次,所以執行效率較低。解釋器的工作就是解釋性語言中,負責「翻譯」原始碼的程式。
下面我們更詳細地討論一下編譯型語言和解釋性語言的運作方式。
一、編譯型語言與解釋型語言
我們知道,對於一段C語言程式碼,需要經過預編譯、編譯、彙編和鏈接,才能成為可執行的二進位。以hello.c為例:
#include<stdio.h> int main(){ printf("hello world"); return 1; }
對於這段C程式碼,main是程式入口函數,實作的功能是列印字串「hello world」 到螢幕上。編譯與執行過程如圖1所示。
圖1 編譯型語言的執行示意圖
第1步:C語言程式碼預處理(例如依賴處理、宏替換等)。如以上程式碼範例,#inlcude
第2步:編譯。編譯器會把C語言翻譯成組合語言程序,一條C語言通常便以為多條彙編程式碼。同時編譯器會對程式進行最佳化,產生目標組譯程式。
第3步:編譯得到的組譯語言透過組譯器再彙編成目標程式hello.o。
第4步:連結。程式中往往包含一些共享目標文件,如範例程式中的printf()函數,位於靜態庫,需要經過連結器(如Uinx連接器ld)進行連結。
以C語言為代表的編譯型語言,程式碼發生更新都要經過以上步驟:
我們區別編譯型語言與解釋型語言,主要立足於原始碼被編譯成目標平台CPU指令的時機。對於編譯型語言,編譯結果已經是針對目前CPU體系的指令;而解釋型語言,需要先編譯成中間碼,再經由該解釋型語言的特定虛擬機,翻譯成特定CPU體系的指令被執行。解釋型語言是在運作過程中,翻譯為目標平台的指令。常說解釋型語言“慢”,主要也是慢在這裡。
在PHP7中,原始碼首先將進行詞法分析,將原始碼切割為多個字串單元,分割後的字串稱為Token。而一個獨立的Token無法表達完整語意,需經過語法分析階段,將Token轉換為抽象語法樹(簡稱AST)。之後,抽象語法樹被轉換為機器指令執行。在PHP中,這些指令稱為opcode(後文會對opcode做更詳細的解釋,此處讀者可以看待為CPU指令)。
到AST的生成這一步,編譯型語言與解釋型語言所需經歷的過程相似。從抽象語法樹之後開始產生差異。
圖2是PHP(如無特殊說明,本章提到的PHP均為PHP7版本)程式碼被執行的簡化步驟,其中最後一步的左側分支,是編譯型語言的過程。
圖2 以PHP為例解釋型語言的執行示意圖
第1步:原始碼透過詞法分析得到Token;
第2步:基於語法分析器產生抽象語法樹(AST);
第3步:抽象語法樹轉換為Opcodes (opcode指令集合),PHP解釋執行Opcodes。
接下來我們在基本步驟的基礎上,細化PHP語言的執行原理,試著更清楚地建立認知。
二、PHP7的執行原理概述
首先我們補充說明下前文提到的PHP7程式執行過程,請參考圖3。
圖3 PHP7語言所寫的程式的執行過程圖
#第1步:詞法分析將PHP程式碼轉換為有意義的標識Token。該步驟的詞法分析器使用Re2c實現的。
第2步:语法分析将Token和符合文法规则的代码生成抽象语法树。语法分析器基于Bison实现。语法分析使用了巴科斯范式(BNF)来表达文法规则,Bison借助状态机、状态转移表和压栈、出栈等一系列操作,生成抽象语法树。
第3步:上步的抽象语法树生成对应的opcode,被虚拟机执行。opcode是PHP7定义的一组指令标识,指令对应着相应的handler(处理函数)。当虚拟机调用opcode,会找到opcode背后的处理函数,执行真正的处理。以我们常见的echo语句为例,其对应的opcode便是ZEND_ECHO。
注意:这里为了便于理解词法分析和语法分析过程,将两者分开描述。但实际情况,出于效率考虑,两个过程并非完全独立。
下面,我们通过一段示例代码,来建立PHP7运转的初步理解。
示例代码如下:
<?phpecho "hello world";
从图3可知,这段代码首先会被切割为Token。
1. Token
Token是PHP代码被切割成的有意义的标识。本书介绍的PHP7版本中有137 种Token,在zend_language_parser.h文件中做了定义:
/* Tokens. */#define END 0#define T_INCLUDE 258#define T_INCLUDE_ONCE 259…#define T_ERROR 392
更多Token的含义,感兴趣的读者可以参考《PHP 7底层设计与源码实现》附录。
PHP提供了token_get_all()函数来获取PHP代码被切割后的Token,可以在深入源码学习前,粗略查看PHP代码被切割后的Token。如下代码片段:
/home/vagrant/php7/bin/php –r 'print_r(Token_get_all("<?php echo \"hello world\";"));'
输出结果为:
Array ( [0] => Array ( [0] => 379 [1] => <?php [2] => 1 ) [1] => Array ( [0] => 328 [1] => echo [2] => 1 ) [2] => Array ( [0] => 382 [1] => [2] => 1 ) [3] => Array ( [0] => 323 [1] => "hello world" [2] => 1 ) [4] => ; )
上文输出中,二维数组的每个成员数组第一个值为Token对应的枚举值;第二个值为Token对应的原始字符串内容;第三个值为代码对应的行号。可以看出,词法解析器将
1)文本“
#dfine T_OPEN_TAG 379
不难理解,它是PHP代码的起始tag,也就是
2)echo对应的Token是T_ECHO:
#define T_ECHO 328
3)源码中的空格,对应的Token叫T_WHITESPACE,值为382:
#define T_WHITESPACE 382
4)字符串“hello world”对应的Token值为323:
#define T_CONSTANT_ENCAPSED_STRING 323
可见,Token就是一个个的“词块”,但是单独存在的词块不能表达完整的语义,还需要借助规则进行组织串联。语法分析器就是这个组织者。它会检查语法、匹配Token,对Token进行关联。
PHP7中,组织串联的产物就是抽象语法树(Abstract Syntax Tree,AST)。
2. AST
AST是PHP7版本新特性。在这之前的版本,PHP代码的执行过程中没有生成AST这一步。PHP7对抽象语法树的支持,实现了PHP编译器和解释器解耦,有效提升了可维护性。
顾名思义,抽象语法树具有树状结构。AST的节点分为多种类型,对应着不同的PHP语法。在当前章节,我们可以认为节点类型是对语法规则的抽象,例如赋值语句,生成的抽象语法树节点为ZEND_AST_ASSIGN。而赋值语句的左右操作数,又将作为ZEND_AST_ASSIGN类型节点的孩子。通过这样的节点关系,构建出抽象语法树。
如果读者希望一睹为快,可以直接跳到本书第13章函数的实现,其中图片描绘了一段简单的PHP代码生成的抽象语法树。
在这里,我们推荐读者了解下PhpParser工具,可以用它来查看PHP代码生成的AST。
注意:PHP-Parser是PHP7内核作者之一nikic编写的将PHP源码生成AST的工具。源码见https://github.com/nikic/PHP-...
3. Opcodes
AST扮演了源码到中间代码的临时存储介质的角色,还需要将其转换为opcode,才能被引擎直接执行。Opcode只是单条指令,Opcodes是opcode的集合形式,是PHP执行过程中的中间代码,类似Java中的字节码。生成之后由虚拟机执行。
我们知道,PHP工程优化措施中有个比较常见的“开启Opcache”,指的就是这里的Opcodes的缓存(Opcodes Cache)。通过省去从源码到opcode的阶段,引擎可以直接执行缓存的opcode,以此提升性能。
借助vld插件,可以直观地看到一段PHP代码生成的opcode:
php -dvld.active=1 hello.php
经过过滤整理,对应的opcode为:
line op 1 ECHO 2 RETURN
其实在源码实现中,上述代码生成的opcode及handler为:
ZEND_ECHO // handler: ZEND_ECHO_SPEC_CONST_HANDLERZEND_RETURN // handler: ZEND_RETURN_SPEC_CONST_HANDLER
可见,ZEND_ECHO对应的handler是ZEND_ECHO_SPEC_CONST_HANDLER。此handler的实现的功能便是预期的“hello world”语句的输出。
相关推荐:《PHP7新特性手册》
以上是PHP7語言的執行原理(PHP7源碼分析)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

在PHP中,應使用password_hash和password_verify函數實現安全的密碼哈希處理,不應使用MD5或SHA1。1)password_hash生成包含鹽值的哈希,增強安全性。 2)password_verify驗證密碼,通過比較哈希值確保安全。 3)MD5和SHA1易受攻擊且缺乏鹽值,不適合現代密碼安全。

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP類型提示提升代碼質量和可讀性。 1)標量類型提示:自PHP7.0起,允許在函數參數中指定基本數據類型,如int、float等。 2)返回類型提示:確保函數返回值類型的一致性。 3)聯合類型提示:自PHP8.0起,允許在函數參數或返回值中指定多個類型。 4)可空類型提示:允許包含null值,處理可能返回空值的函數。

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。
