我們常用的高階語言有很多種,比較出名的有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中文網其他相關文章!

PHP在現代編程中仍然是一個強大且廣泛使用的工具,尤其在web開發領域。 1)PHP易用且與數據庫集成無縫,是許多開發者的首選。 2)它支持動態內容生成和麵向對象編程,適合快速創建和維護網站。 3)PHP的性能可以通過緩存和優化數據庫查詢來提升,其廣泛的社區和豐富生態系統使其在當今技術棧中仍具重要地位。

在PHP中,弱引用是通過WeakReference類實現的,不會阻止垃圾回收器回收對象。弱引用適用於緩存系統和事件監聽器等場景,需注意其不能保證對象存活,且垃圾回收可能延遲。

\_\_invoke方法允許對象像函數一樣被調用。 1.定義\_\_invoke方法使對象可被調用。 2.使用$obj(...)語法時,PHP會執行\_\_invoke方法。 3.適用於日誌記錄和計算器等場景,提高代碼靈活性和可讀性。

Fibers在PHP8.1中引入,提升了並發處理能力。 1)Fibers是一種輕量級的並發模型,類似於協程。 2)它們允許開發者手動控制任務的執行流,適合處理I/O密集型任務。 3)使用Fibers可以編寫更高效、響應性更強的代碼。

PHP社區提供了豐富的資源和支持,幫助開發者成長。 1)資源包括官方文檔、教程、博客和開源項目如Laravel和Symfony。 2)支持可以通過StackOverflow、Reddit和Slack頻道獲得。 3)開發動態可以通過關注RFC了解。 4)融入社區可以通過積極參與、貢獻代碼和學習分享來實現。

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP不是在消亡,而是在不斷適應和進化。 1)PHP從1994年起經歷多次版本迭代,適應新技術趨勢。 2)目前廣泛應用於電子商務、內容管理系統等領域。 3)PHP8引入JIT編譯器等功能,提升性能和現代化。 4)使用OPcache和遵循PSR-12標準可優化性能和代碼質量。

PHP的未來將通過適應新技術趨勢和引入創新特性來實現:1)適應云計算、容器化和微服務架構,支持Docker和Kubernetes;2)引入JIT編譯器和枚舉類型,提升性能和數據處理效率;3)持續優化性能和推廣最佳實踐。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

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

WebStorm Mac版
好用的JavaScript開發工具

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3 Linux新版
SublimeText3 Linux最新版

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