目錄
彙編
階段3 - 彙編
結論
>
> PHP在執行過程中如何處理會話管理?
首頁 後端開發 php教程 PHP如何執行 - 從源代碼到渲染

PHP如何執行 - 從源代碼到渲染

Feb 10, 2025 am 10:11 AM

PHP如何執行 - 從源代碼到渲染

本文由Younes Rafie進行了同行評審。感謝SitePoint所有的同行評審員製作SitePoint內容的最佳狀態!


>受Ruby代碼如何執行的最新文章的啟發,本文涵蓋了PHP代碼的執行過程。

PHP如何執行 - 從源代碼到渲染鑰匙要點

PHP代碼的執行涉及四個階段:Lexing,解析,編譯和解釋。每個階段在將PHP源代碼轉換為機器可讀代碼的過程中至關重要。

> Lexing或令牌化是將字符串(PHP源代碼)變成一個令牌序列的過程。每個令牌是其匹配值的命名標識符。此階段還存儲lexeme和匹配令牌的行號。 > 解析階段
    驗證令牌順序的有效性,並生成抽象語法樹(AST)。 AST是在編譯階段使用的源代碼的樹視圖。 彙編階段通過遍歷AST並進行優化,例如使用字面參數和折疊恆定的數學表達式進行優化。可以使用OPCACHE,VLD和PHPDBG檢查此階段的輸出。
  • 解釋階段是在Zend Engine(ZE)VM上運行Opcodes的最後階段。此階段的輸出是您的PHP腳本通過echo,print,var_dump等命令輸出的內容。
  • >
  • 簡介
  • >當我們執行PHP代碼時,引擎蓋下發生了很多事情。從廣義上講,執行代碼時,PHP解釋器將經歷四個階段:>
  • Lexing
  • 解析

彙編

解釋

  1. >本文將瀏覽這些階段,並展示我們如何查看每個階段的輸出,以真正查看發生了什麼。請注意,雖然某些使用的擴展程序應該已經是您的PHP安裝的一部分(例如Tokenizer和opcache),但需要手動安裝和啟用其他擴展程序(例如,PHP-ast和VLD)。
  2. 階段1 - Lexing
  3. Lexing(或令牌化)是將字符串(在這種情況下為PHP源代碼)轉換為令牌序列的過程。令牌只是其匹配的值的命名標識符。 PHP使用re2c從zend_language_scanner.l定義文件。
  4. >我們可以通過令牌擴展名看到Lexing階段的輸出:
  5. >輸出:
  6. $code = <<<'code'
    <span><span><?php
    </span></span><span><span>$a = 1;
    </span></span><span>code<span>;
    </span></span><span>
    </span><span><span>$tokens = token_get_all($code);
    </span></span><span>
    </span><span><span>foreach ($tokens as $token) {
    </span></span><span>    <span>if (is_array($token)) {
    </span></span><span>        <span>echo "Line <span><span>{$token[2]}</span>: "</span>, token_name($token[0]), " ('<span><span>{$token[1]}</span>')"</span>, PHP_EOL;
    </span></span><span>    <span>} else {
    </span></span><span>        <span>var_dump($token);
    </span></span><span>    <span>}
    </span></span><span><span>}
    </span></span>
    登入後複製
    登入後複製

    >從上述輸出中有幾個值得注意的點。第一個點是,並非所有源代碼的所有部分都命名為令牌。相反,某些符號本身被視為令牌(例如=,;,:,?等)。第二點是,Lexer實際上做的不只是簡單地輸出一個令牌流。在大多數情況下,它也存儲了lexeme(由令牌匹配的值)和匹配令牌的行號(用於堆棧跟踪之類的內容)。

    階段2 - 解析

    也生成了解析器,這次是通過BNF語法文件與野牛一起生成的。 PHP使用LALR(1)(向前,從左到右)無上下文語法。前面的外觀僅意味著解析器能夠在解析時可能會遇到的歧義。從左到右的部分意味著它從左到右解析令牌流。

    >

    >生成的解析器階段將令牌流從Lexer作為輸入中獲取,並有兩個作業。首先,它通過嘗試將其與BNF語法文件中定義的任何語法規則相匹配,從而驗證令牌順序的有效性。這樣可以確保令牌流中的代幣形成有效的語言構造。解析器的第二個作業是生成

    抽象語法樹

    (AST) - 下一階段將使用的源代碼的樹視圖(彙編)。 我們可以使用php-ast擴展名來查看的一種

    。內部AST並沒有直接暴露,因為與之合作(在一致性和一般可用性方面)並不是特別“乾淨”,因此PHP-AST擴展對其進行了一些轉換以使其可以更好地使用。 >讓我們看一下基本代碼的AST:> >輸出:

    Line 1: T_OPEN_TAG ('<?php
    ')
    Line 2: T_VARIABLE ('$a')
    Line 2: T_WHITESPACE (' ')
    string(1) "="
    Line 2: T_WHITESPACE (' ')
    Line 2: T_LNUMBER ('1')
    string(1) ";"
    
    登入後複製
    登入後複製
    樹節點(通常是類型的astnode)具有多個屬性:

    $code = <<<'code'
    <span><span><?php
    </span></span><span><span>$a = 1;
    </span></span><span>code<span>;
    </span></span><span>
    </span><span><span>print_r(ast<span>\parse_code</span>($code, 30));
    </span></span>
    登入後複製
    登入後複製
    類型 - 描繪節點類型的整數值;每個都有相應的常數(例如AST_STMT_LIST => 132,AST_ASSIGN => 517,AST_VAR => 256)

    >標誌 - 一個指定過載行為的整數(例如,ASTAST_BINARD_OP節點將具有區分發生哪些二進制操作的標誌)

    Lineno
    lineno - 線號,從較早的令牌信息中可以看出
  • 兒童 - 子節點,通常會進一步分解該節點的一部分(例如,功能節點將具有孩子:參數,返回類型,身體等)
  • >此階段的AST輸出很方便用於諸如靜態代碼分析儀(例如phan)之類的工具。

    階段3 - 彙編

    彙編階段消耗了AST,它通過遞歸穿越樹來發出opcods。這個階段還進行了一些優化。這些包括通過字面論據(例如strlen(“ ABC”)到int(3))和折疊持續的數學表達式(例如60 * 60 * 24 to int(86400))。

    >我們可以在此階段以多種方式檢查OpCode輸出,包括OPCACHE,VLD和PHPDBG。我將使用VLD為此,因為我覺得輸出更友好。

    >讓我們看看以下file.php腳本的輸出是什麼:

    執行以下命令:
    $code = <<<'code'
    <span><span><?php
    </span></span><span><span>$a = 1;
    </span></span><span>code<span>;
    </span></span><span>
    </span><span><span>$tokens = token_get_all($code);
    </span></span><span>
    </span><span><span>foreach ($tokens as $token) {
    </span></span><span>    <span>if (is_array($token)) {
    </span></span><span>        <span>echo "Line <span><span>{$token[2]}</span>: "</span>, token_name($token[0]), " ('<span><span>{$token[1]}</span>')"</span>, PHP_EOL;
    </span></span><span>    <span>} else {
    </span></span><span>        <span>var_dump($token);
    </span></span><span>    <span>}
    </span></span><span><span>}
    </span></span>
    登入後複製
    登入後複製
    >

    我們的輸出是:
    Line 1: T_OPEN_TAG ('<?php
    ')
    Line 2: T_VARIABLE ('$a')
    Line 2: T_WHITESPACE (' ')
    string(1) "="
    Line 2: T_WHITESPACE (' ')
    Line 2: T_LNUMBER ('1')
    string(1) ";"
    
    登入後複製
    登入後複製

    > Opcodes類似於原始源代碼,足以與基本操作一起進行。 (我不會深入研究本文中的opcodes的詳細信息,因為這本身將需要幾個整個文章。)在上面腳本中沒有在OpCode級別上應用優化,但是正如我們所看到的,編譯階段通過解決恆定條件(php_version ==='7.1.0-dev')來做出一些。
    $code = <<<'code'
    <span><span><?php
    </span></span><span><span>$a = 1;
    </span></span><span>code<span>;
    </span></span><span>
    </span><span><span>print_r(ast<span>\parse_code</span>($code, 30));
    </span></span>
    登入後複製
    登入後複製
    > OPCACHE不僅可以簡單地緩存OPCODE(因此繞過Lexing,解析和編譯階段)。它還包含許多不同級別的優化。讓我們將優化級別提高到四個傳球,以查看出來的內容:

    >

    >命令:

    >輸出:

    ast\Node Object (
        [kind] => 132
        [flags] => 0
        [lineno] => 1
        [children] => Array (
            [0] => ast\Node Object (
                [kind] => 517
                [flags] => 0
                [lineno] => 2
                [children] => Array (
                    [var] => ast\Node Object (
                        [kind] => 256
                        [flags] => 0
                        [lineno] => 2
                        [children] => Array (
                            [name] => a
                        )
                    )
                    [expr] => 1
                )
            )
        )
    )
    
    登入後複製

    >我們可以看到恆定條件已被刪除,並且兩個迴聲指令已被壓縮到單個指令中。這些只是對Opcache在腳本的Opcodes上進行的許多優化的味道。不過,我不會瀏覽本文的各種優化級別,因為這本身也是一篇文章。

    >階段4 - 解釋
    <span>if (PHP_VERSION === '7.1.0-dev') {
    </span>    <span>echo 'Yay', PHP_EOL;
    </span><span>}
    </span>
    登入後複製

    >最後階段是對opcodes的解釋。這是Opcodes在Zend Engine(ZE)VM上運行的地方。對於這個階段,實際上幾乎沒有什麼可說的(至少從高級角度來看)。輸出幾乎是您通過echo,print,var_dump等命令輸出輸出的任何內容。

    >因此,這是一個有趣的事實,而不是在此階段挖掘任何復雜的事實:PHP在生成自己的VM時需要自己作為依賴性。這是因為VM是由PHP腳本生成的,因為它更簡單並且更易於維護。

    結論

    >我們已經簡要介紹了PHP解釋器在運行PHP代碼時通過的四個階段。這涉及使用各種擴展(包括令牌,PHP-ast,opcache和vld)來操縱和查看每個階段的輸出。

    >我希望本文能夠幫助您對PHP的解釋器有更好的整體理解,並顯示了Opcache擴展的重要性(用於其緩存和優化能力)。

    經常詢問有關PHP執行過程的問題(常見問題解答)

    > PHP解釋器在執行過程中的作用是什麼?它負責將PHP源代碼轉換為機器可讀代碼。解釋器逐行讀取PHP腳本,解釋每行並執行必要的操作。它還負責在執行過程中處理錯誤和例外。 PHP解釋器是PHP運行時環境的關鍵組成部分,其中還包括Web服務器和PHP擴展。 PHP執行過程。它負責解析PHP腳本,將其編譯到字節碼中,然後執行字節碼。 PHP引擎使用兩步過程來執行PHP腳本。首先,它解析PHP腳本並將其轉換為抽象語法樹(AST)。然後,將AST編譯到字節碼中並執行。 PHP引擎還包括一個內存管理器和一個垃圾收集器,以在執行過程中管理內存使用量。

    >

    > PHP的命令行接口和Web服務器接口之間有什麼區別? -line接口(CLI)和Web服務器接口是運行PHP腳本的兩種不同方法。 CLI用於從命令行運行PHP腳本,而Web服務器接口則用於響應Web請求來運行PHP腳本。兩個接口之間的主要區別是它們處理輸入和輸出的方式。在CLI中,從命令行讀取輸入,並將輸出寫入控制台。在Web服務器接口中,從HTTP請求讀取輸入,並將輸出寫入HTTP響應。

    >

    PHP在執行過程中如何處理錯誤?

    php具有強大的錯誤處理。允許其在執行過程中處理錯誤的機制。發生錯誤時,PHP會生成錯誤消息並將其發送到錯誤處理程序。錯誤處理程序可以根據錯誤報告設置顯示錯誤消息,將其記錄或忽略。 PHP還支持異常處理,這使其可以以更結構化和易於管理的方式處理錯誤。 >

    > php擴展在執行過程中的作用是什麼?

    php擴展是在PHP語言中添加新功能和功能的模塊。在執行過程中,它們被加載到PHP運行時環境中,可用於執行從數據庫訪問到圖像處理的廣泛任務。 PHP擴展名為C編寫,並編譯為機器代碼,這使其非常快速有效。它們是PHP生態系統的關鍵組成部分,並有助於其靈活性和功率。

    >

    > PHP如何優化執行過程?

    PHP使用多種技術來優化執行過程。這些技術之一是OpCode緩存,其中涉及將PHP引擎生成的字節碼存儲在內存中,以便可以在後續執行中重複使用。這消除了每次執行PHP腳本的必要性,從而大大提高了性能。 PHP還使用Just-In-time(JIT)彙編,其中涉及在運行時將字節碼編譯到機器代碼中以進一步提高性能。

    >

    PHP在執行過程中如何處理內存管理? PHP具有內置內存管理器,可以在執行過程中處理內存分配和Deallocation。內存管理器根據需要為變量和數據結構分配內存,並在不再需要內存時對內存進行交易。 PHP還具有一個垃圾收集器,該垃圾收集器會自動釋放不再使用的內存。這有助於防止內存洩漏並將內存使用控制在控制之下。

    > Web服務器在PHP執行過程中的作用是什麼?

    >

    > Web服務器在PHP執行中起關鍵作用過程。它負責處理HTTP請求,對這些請求運行PHP腳本,然後將HTTP響應發送回客戶端。 Web服務器與PHP解釋器和PHP引擎緊密合作,以執行PHP腳本並生成動態網頁。 PHP最常用的Web服務器是Apache和Nginx。 MySQL,PostgreSQL和SQLite。它在執行過程中使用數據庫特異性擴展與這些數據庫進行交互。這些擴展提供了一組功能,可用於連接到數據庫,執行SQL查詢,獲取結果並處理錯誤。 PHP還支持PDO(PHP數據對象)擴展名,該擴展提供了數據庫交互的數據庫-Nostic接口。

    > PHP在執行過程中如何處理會話管理?

    PHP對會話管理具有內置支持,這使其可以在不同的HTTP請求之間維護狀態。啟動會話後,PHP會創建唯一的會話ID,並將其存儲在客戶端瀏覽器上的cookie中。然後,此會話ID通過每個後續請求發送回服務器,允許PHP識別客戶端並檢索相應的會話數據。 PHP的會話管理功能使在Web應用程序中實現用戶身份驗證,購物車和其他狀態功能變得易於實現。

以上是PHP如何執行 - 從源代碼到渲染的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱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

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

熱工具

記事本++7.3.1

記事本++7.3.1

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

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

PHP 8.1中的枚舉(枚舉)是什麼? PHP 8.1中的枚舉(枚舉)是什麼? Apr 03, 2025 am 12:05 AM

PHP8.1中的枚舉功能通過定義命名常量增強了代碼的清晰度和類型安全性。 1)枚舉可以是整數、字符串或對象,提高了代碼可讀性和類型安全性。 2)枚舉基於類,支持面向對象特性,如遍歷和反射。 3)枚舉可用於比較和賦值,確保類型安全。 4)枚舉支持添加方法,實現複雜邏輯。 5)嚴格類型檢查和錯誤處理可避免常見錯誤。 6)枚舉減少魔法值,提升可維護性,但需注意性能優化。

會話如何劫持工作,如何在PHP中減輕它? 會話如何劫持工作,如何在PHP中減輕它? Apr 06, 2025 am 12:02 AM

會話劫持可以通過以下步驟實現:1.獲取會話ID,2.使用會話ID,3.保持會話活躍。在PHP中防範會話劫持的方法包括:1.使用session_regenerate_id()函數重新生成會話ID,2.通過數據庫存儲會話數據,3.確保所有會話數據通過HTTPS傳輸。

描述紮實的原則及其如何應用於PHP的開發。 描述紮實的原則及其如何應用於PHP的開發。 Apr 03, 2025 am 12:04 AM

SOLID原則在PHP開發中的應用包括:1.單一職責原則(SRP):每個類只負責一個功能。 2.開閉原則(OCP):通過擴展而非修改實現變化。 3.里氏替換原則(LSP):子類可替換基類而不影響程序正確性。 4.接口隔離原則(ISP):使用細粒度接口避免依賴不使用的方法。 5.依賴倒置原則(DIP):高低層次模塊都依賴於抽象,通過依賴注入實現。

解釋PHP中的晚期靜態綁定(靜態::)。 解釋PHP中的晚期靜態綁定(靜態::)。 Apr 03, 2025 am 12:04 AM

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

什麼是REST API設計原理? 什麼是REST API設計原理? Apr 04, 2025 am 12:01 AM

RESTAPI設計原則包括資源定義、URI設計、HTTP方法使用、狀態碼使用、版本控制和HATEOAS。 1.資源應使用名詞表示並保持層次結構。 2.HTTP方法應符合其語義,如GET用於獲取資源。 3.狀態碼應正確使用,如404表示資源不存在。 4.版本控制可通過URI或頭部實現。 5.HATEOAS通過響應中的鏈接引導客戶端操作。

您如何在PHP中有效處理異常(嘗試,捕捉,最後,投擲)? 您如何在PHP中有效處理異常(嘗試,捕捉,最後,投擲)? Apr 05, 2025 am 12:03 AM

在PHP中,異常處理通過try,catch,finally,和throw關鍵字實現。 1)try塊包圍可能拋出異常的代碼;2)catch塊處理異常;3)finally塊確保代碼始終執行;4)throw用於手動拋出異常。這些機制幫助提升代碼的健壯性和可維護性。

PHP中的匿名類是什麼?您何時可以使用它們? PHP中的匿名類是什麼?您何時可以使用它們? Apr 04, 2025 am 12:02 AM

匿名類在PHP中的主要作用是創建一次性使用的對象。 1.匿名類允許在代碼中直接定義沒有名字的類,適用於臨時需求。 2.它們可以繼承類或實現接口,增加靈活性。 3.使用時需注意性能和代碼可讀性,避免重複定義相同的匿名類。

See all articles