国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
關(guān)鍵要點(diǎn)
先前實(shí)現(xiàn)的缺點(diǎn)
更新詞法分析器
更新解析器
更新編譯階段
更新Zend虛擬機(jī)
結(jié)論
首頁(yè) 後端開(kāi)發(fā) php教程 重新實(shí)現(xiàn)PHP中的範(fàn)圍運(yùn)算符

重新實(shí)現(xiàn)PHP中的範(fàn)圍運(yùn)算符

Feb 15, 2025 am 09:36 AM

SitePoint精彩文章推薦:改進(jìn)後的PHP範(fàn)圍運(yùn)算符實(shí)現(xiàn)

本文經(jīng)作者授權(quán)轉(zhuǎn)載於SitePoint。以下內(nèi)容由Thomas Punt撰寫(xiě),介紹了PHP範(fàn)圍運(yùn)算符的改進(jìn)實(shí)現(xiàn)方法。如果您對(duì)PHP內(nèi)部機(jī)制和為喜愛(ài)的編程語(yǔ)言添加功能感興趣,那麼現(xiàn)在正是學(xué)習(xí)的好時(shí)機(jī)!

本文假設(shè)讀者能夠從源代碼構(gòu)建PHP。如果不是這樣,請(qǐng)先閱讀PHP內(nèi)部機(jī)製書(shū)籍的“構(gòu)建PHP”章節(jié)。

Re-Implementing the Range Operator in PHP


在本文的前篇(提示:請(qǐng)確保您已閱讀),我展示了一種在PHP中實(shí)現(xiàn)範(fàn)圍運(yùn)算符的方法。然而,最初的實(shí)現(xiàn)很少是最好的,因此本文旨在探討如何改進(jìn)之前的實(shí)現(xiàn)。

再次感謝Nikita Popov校對(duì)本文!

關(guān)鍵要點(diǎn)

  • Thomas Punt重新實(shí)現(xiàn)了PHP中的範(fàn)圍運(yùn)算符,將計(jì)算邏輯從Zend虛擬機(jī)中移出,從而允許在常量表達(dá)式上下文中使用範(fàn)圍運(yùn)算符。
  • 此重新實(shí)現(xiàn)能夠在編譯時(shí)(對(duì)於字面量操作數(shù))或運(yùn)行時(shí)(對(duì)於動(dòng)態(tài)操作數(shù))進(jìn)行計(jì)算。這不僅為Opcache用戶帶來(lái)了一點(diǎn)好處,而且允許將常量表達(dá)式功能與範(fàn)圍運(yùn)算符一起使用。
  • 重新實(shí)現(xiàn)過(guò)程涉及更新詞法分析器、解析器、編譯階段和Zend虛擬機(jī)。詞法分析器實(shí)現(xiàn)保持不變,而解析器實(shí)現(xiàn)與之前部分相同。編譯階段不需要更新Zend/zend_compile.c文件,因?yàn)樗呀?jīng)包含處理二元運(yùn)算的必要邏輯。 Zend虛擬機(jī)已更新為在運(yùn)行時(shí)處理ZEND_RANGE操作碼的執(zhí)行。
  • 在本系列的第三部分中,Punt計(jì)劃通過(guò)介紹如何重載此運(yùn)算符來(lái)構(gòu)建此實(shí)現(xiàn)。這將使對(duì)象能夠用作操作數(shù),並為字符串添加適當(dāng)?shù)闹С帧?

先前實(shí)現(xiàn)的缺點(diǎn)

最初的實(shí)現(xiàn)將範(fàn)圍運(yùn)算符的所有邏輯都放在Zend虛擬機(jī)中,這迫使計(jì)算在執(zhí)行ZEND_RANGE操作碼時(shí)純粹在運(yùn)行時(shí)進(jìn)行。這不僅意味著對(duì)於字面量操作數(shù),計(jì)算不能轉(zhuǎn)移到編譯時(shí),而且還意味著某些功能根本無(wú)法工作。

在此實(shí)現(xiàn)中,我們將範(fàn)圍運(yùn)算符邏輯從Zend虛擬機(jī)中移出,以便能夠在編譯時(shí)(對(duì)於字面量操作數(shù))或運(yùn)行時(shí)(對(duì)於動(dòng)態(tài)操作數(shù))進(jìn)行計(jì)算。這不僅為Opcache用戶帶來(lái)了一點(diǎn)好處,更重要的是允許將常量表達(dá)式功能與範(fàn)圍運(yùn)算符一起使用。

例如:

// 作為常量定義
const AN_ARRAY = 1 |> 100;

// 作為初始屬性定義
class A
{
    private $a = 1 |> 2;
}

// 作為可選參數(shù)的默認(rèn)值:
function a($a = 1 |> 2)
{
    //
}

因此,事不宜遲,讓我們重新實(shí)現(xiàn)範(fàn)圍運(yùn)算符。

更新詞法分析器

詞法分析器實(shí)現(xiàn)保持完全不變。令牌首先在Zend/zend_language_scanner.l(約1200行)中註冊(cè):

<st_in_scripting>"|>" {
</st_in_scripting>    RETURN_TOKEN(T_RANGE);
}

然後在Zend/zend_language_parser.y(約220行)中聲明:

// 作為常量定義
const AN_ARRAY = 1 |> 100;

// 作為初始屬性定義
class A
{
    private $a = 1 |> 2;
}

// 作為可選參數(shù)的默認(rèn)值:
function a($a = 1 |> 2)
{
    //
}

必須再次通過(guò)進(jìn)入ext/tokenizer目錄並執(zhí)行tokenizer_data_gen.sh文件來(lái)重新生成標(biāo)記器擴(kuò)展。

更新解析器

解析器實(shí)現(xiàn)與之前部分相同。我們?cè)俅瓮ㄟ^(guò)將T_RANGE令牌添加到以下行的末尾來(lái)聲明運(yùn)算符的優(yōu)先級(jí)和結(jié)合性(約70行):

<st_in_scripting>"|>" {
</st_in_scripting>    RETURN_TOKEN(T_RANGE);
}

然後,我們?cè)俅胃耬xpr_without_variable產(chǎn)生式規(guī)則,但這次語(yǔ)義動(dòng)作(花括號(hào)內(nèi)的代碼)將略有不同。使用以下代碼更新它(我將其放在T_SPACESHIP規(guī)則下方,約930行):

%token T_RANGE           "|> (T_RANGE)"

這次,我們使用了zend_ast_create_binary_op函數(shù)(而不是zend_ast_create函數(shù)),它為我們創(chuàng)建了一個(gè)ZEND_AST_BINARY_OP節(jié)點(diǎn)。 zend_ast_create_binary_op採(cǎi)用一個(gè)操作碼名稱(chēng),該名稱(chēng)將在編譯階段用於區(qū)分二元運(yùn)算。

由於我們現(xiàn)在正在重用ZEND_AST_BINARY_OP節(jié)點(diǎn)類(lèi)型,因此無(wú)需像之前在Zend/zend_ast.h文件中那樣定義新的ZEND_AST_RANGE節(jié)點(diǎn)類(lèi)型。

更新編譯階段

這次,無(wú)需更新Zend/zend_compile.c文件,因?yàn)樗呀?jīng)包含處理二元運(yùn)算的必要邏輯。因此,我們只需通過(guò)將我們的運(yùn)算符設(shè)為ZEND_AST_BINARY_OP節(jié)點(diǎn)來(lái)重用此邏輯。

以下是zend_compile_binary_op函數(shù)的簡(jiǎn)化版本:

%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL T_SPACESHIP T_RANGE

正如我們所看到的,它與我們上次創(chuàng)建的zend_compile_range函數(shù)非常相似。兩個(gè)重要的區(qū)別在於如何獲取操作碼類(lèi)型以及當(dāng)兩個(gè)操作數(shù)都是字面量時(shí)會(huì)發(fā)生什麼。

操作碼類(lèi)型這次是從AST節(jié)點(diǎn)獲取的(而不是像上次那樣硬編碼),因?yàn)閆END_AST_BINARY_OP節(jié)點(diǎn)存儲(chǔ)此值(如新的產(chǎn)生式規(guī)則的語(yǔ)義動(dòng)作所示)以區(qū)分二元運(yùn)算。當(dāng)兩個(gè)操作數(shù)都是字面量時(shí),將調(diào)用zend_try_ct_eval_binary_op函數(shù)。此函數(shù)如下所示:

    |   expr T_RANGE expr
            { $$ = zend_ast_create_binary_op(ZEND_RANGE, , ); }

該函數(shù)根據(jù)操作碼類(lèi)型從Zend/zend_opcode.c中的get_binary_op函數(shù)(源代碼)獲取回調(diào)。這意味著我們需要接下來(lái)更新此函數(shù)以適應(yīng)ZEND_RANGE操作碼。將以下case語(yǔ)句添加到get_binary_op函數(shù)(約750行):

void zend_compile_binary_op(znode *result, zend_ast *ast) /* {{{ */
{
    zend_ast *left_ast = ast->child[0];
    zend_ast *right_ast = ast->child[1];
    uint32_t opcode = ast->attr;

    znode left_node, right_node;
    zend_compile_expr(&left_node, left_ast);
    zend_compile_expr(&right_node, right_ast);

    if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) {
        if (zend_try_ct_eval_binary_op(&result->u.constant, opcode,
                &left_node.u.constant, &right_node.u.constant)
        ) {
            result->op_type = IS_CONST;
            zval_ptr_dtor(&left_node.u.constant);
            zval_ptr_dtor(&right_node.u.constant);
            return;
        }
    }

    do {
        // redacted code
        zend_emit_op_tmp(result, opcode, &left_node, &right_node);
    } while (0);
}
/* }}} */

現(xiàn)在我們必須定義range_function函數(shù)。這將在Zend/zend_operators.c文件中與所有其他運(yùn)算符一起完成:

static inline zend_bool zend_try_ct_eval_binary_op(zval *result, uint32_t opcode, zval *op1, zval *op2) /* {{{ */
{
    binary_op_type fn = get_binary_op(opcode);

    /* don't evaluate division by zero at compile-time */
    if ((opcode == ZEND_DIV || opcode == ZEND_MOD) &&
        zval_get_long(op2) == 0) {
        return 0;
    } else if ((opcode == ZEND_SL || opcode == ZEND_SR) &&
        zval_get_long(op2)      return 0;
    }

    fn(result, op1, op2);
    return 1;
}
/* }}} */

函數(shù)原型包含兩個(gè)新的宏:ZEND_API和ZEND_FASTCALL。 ZEND_API用於通過(guò)使函數(shù)可用於編譯為共享對(duì)象的擴(kuò)展來(lái)控制函數(shù)的可見(jiàn)性。 ZEND_FASTCALL用於確保使用更高效的調(diào)用約定,其中前兩個(gè)參數(shù)將使用寄存器而不是堆棧傳遞(對(duì)於x86上的64位構(gòu)建比32位構(gòu)建更相關(guān))。

函數(shù)體與我們?cè)谏弦黄恼轮械腪end/zend_vm_def.h文件中所擁有的非常相似。 VM特定的內(nèi)容不再存在,包括HANDLE_EXCEPTION宏調(diào)用(已替換為return FAILURE;),並且ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION宏調(diào)用已被完全刪除(此檢查和操作需要保留在VM中,因此宏將稍後從VM代碼中調(diào)用)。此外,如前所述,我們避免使用GET_OPn_ZVAL_PTR偽宏(而不是GET_OPn_ZVAL_PTR_DEREF)在VM中處理引用。

另一個(gè)值得注意的區(qū)別是我們正在對(duì)兩個(gè)操作數(shù)應(yīng)用ZVAL_DEFEF以確保正確處理引用。這以前是在VM內(nèi)部使用偽宏GET_OPn_ZVAL_PTR_DEREF完成的,但現(xiàn)在已轉(zhuǎn)移到此函數(shù)中。這樣做不是因?yàn)樗诰幾g時(shí)需要(因?yàn)閷?duì)於編譯時(shí)處理,兩個(gè)操作數(shù)都必須是字面量,並且它們不能被引用),而是因?yàn)樗勾a庫(kù)中的其他位置能夠安全地調(diào)用range_function,而無(wú)需擔(dān)心引用處理。因此,大多數(shù)運(yùn)算符函數(shù)(除了性能至關(guān)重要的地方)都執(zhí)行引用處理,而不是在其VM操作碼定義中執(zhí)行。

最後,我們必須將range_function原型添加到Zend/zend_operators.h文件:

// 作為常量定義
const AN_ARRAY = 1 |> 100;

// 作為初始屬性定義
class A
{
    private $a = 1 |> 2;
}

// 作為可選參數(shù)的默認(rèn)值:
function a($a = 1 |> 2)
{
    //
}

更新Zend虛擬機(jī)

現(xiàn)在我們必須再次更新Zend虛擬機(jī)以在運(yùn)行時(shí)處理ZEND_RANGE操作碼的執(zhí)行。將以下代碼放在Zend/zend_vm_def.h(底部):

<st_in_scripting>"|>" {
</st_in_scripting>    RETURN_TOKEN(T_RANGE);
}

(同樣,操作碼編號(hào)必須比當(dāng)前最高操作碼編號(hào)大一,這可以在Zend/zend_vm_opcodes.h文件的底部看到。)

這次的定義要短得多,因?yàn)樗泄ぷ鞫荚趓ange_function中處理。我們只需調(diào)用此函數(shù),傳入當(dāng)前opline的結(jié)果操作數(shù)即可保存計(jì)算值。從range_function中刪除的異常檢查和跳到下一個(gè)操作碼仍在VM中由對(duì)ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION的調(diào)用處理。此外,如前所述,我們避免使用GET_OPn_ZVAL_PTR偽宏(而不是GET_OPn_ZVAL_PTR_DEREF)在VM中處理引用。

現(xiàn)在通過(guò)執(zhí)行Zend/zend_vm_gen.php文件重新生成VM。

最後,漂亮打印機(jī)需要再次更新Zend/zend_ast.c文件。通過(guò)指定新運(yùn)算符的優(yōu)先級(jí)為170來(lái)更新優(yōu)先級(jí)表註釋?zhuān)s520行):

%token T_RANGE           "|> (T_RANGE)"

然後,在zend_ast_export_ex函數(shù)中插入一個(gè)case語(yǔ)句,以在ZEND_AST_BINARY_OP case語(yǔ)句中處理ZEND_RANGE操作碼(約1300行):

%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL T_SPACESHIP T_RANGE

結(jié)論

本文展示了一種實(shí)現(xiàn)範(fàn)圍運(yùn)算符的替代方法,其中計(jì)算邏輯已從VM中移出。這具有能夠在常量表達(dá)式上下文中使用範(fàn)圍運(yùn)算符的優(yōu)點(diǎn)。

本系列文章的第三部分將在此實(shí)現(xiàn)的基礎(chǔ)上構(gòu)建,介紹如何重載此運(yùn)算符。這將允許對(duì)像用作操作數(shù)(例如來(lái)自GMP庫(kù)的對(duì)像或?qū)崿F(xiàn)__toString方法的對(duì)象)。它還將展示如何為字符串添加適當(dāng)?shù)?/em>支持(不像PHP當(dāng)前範(fàn)圍函數(shù)中看到的支持)。但就目前而言,我希望這能很好地演示ZE在將運(yùn)算符實(shí)現(xiàn)到PHP中時(shí)的一些更深層次的方面。

以上是重新實(shí)現(xiàn)PHP中的範(fàn)圍運(yùn)算符的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願(yuàn)投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請(qǐng)聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

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

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

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

熱門(mén)話題

如何在PHP中實(shí)施身份驗(yàn)證和授權(quán)? 如何在PHP中實(shí)施身份驗(yàn)證和授權(quán)? Jun 20, 2025 am 01:03 AM

tosecurelyhandleauthenticationandationallizationInphp,lofterTheSesteps:1.AlwaysHashPasswordSwithPassword_hash()andverifyusingspasspassword_verify(),usepreparedStatatementStopreventsqlineptions,andStoreSeruserDatain usseruserDatain $ _sessiveferterlogin.2.implementrole-2.imaccessccsccccccccccccccccccccccccc.

我如何了解最新的PHP開(kāi)發(fā)和最佳實(shí)踐? 我如何了解最新的PHP開(kāi)發(fā)和最佳實(shí)踐? Jun 23, 2025 am 12:56 AM

TostaycurrentwithPHPdevelopmentsandbestpractices,followkeynewssourceslikePHP.netandPHPWeekly,engagewithcommunitiesonforumsandconferences,keeptoolingupdatedandgraduallyadoptnewfeatures,andreadorcontributetoopensourceprojects.First,followreliablesource

什麼是PHP,為什麼它用於Web開(kāi)發(fā)? 什麼是PHP,為什麼它用於Web開(kāi)發(fā)? Jun 23, 2025 am 12:55 AM

PHPbecamepopularforwebdevelopmentduetoitseaseoflearning,seamlessintegrationwithHTML,widespreadhostingsupport,andalargeecosystemincludingframeworkslikeLaravelandCMSplatformslikeWordPress.Itexcelsinhandlingformsubmissions,managingusersessions,interacti

如何設(shè)置PHP時(shí)區(qū)? 如何設(shè)置PHP時(shí)區(qū)? Jun 25, 2025 am 01:00 AM

tosetTherightTimeZoneInphp,restate_default_timezone_set()functionAtthestArtofyourscriptWithavalIdidentIdentifiersuchas'america/new_york'.1.usedate_default_default_timezone_set_set()

如何在操作系統(tǒng)(Windows,MacOS,Linux)上安裝PHP? 如何在操作系統(tǒng)(Windows,MacOS,Linux)上安裝PHP? Jun 20, 2025 am 01:02 AM

安裝PHP的方法因操作系統(tǒng)而異,以下是具體步驟:1.Windows用戶可使用XAMPP一鍵安裝包或手動(dòng)配置,下載XAMPP並安裝,選擇PHP組件或?qū)HP加入環(huán)境變量;2.macOS用戶可通過(guò)Homebrew安裝PHP,運(yùn)行相應(yīng)命令安裝並配置Apache服務(wù)器;3.Linux用戶(Ubuntu/Debian)可使用APT包管理器更新源後安裝PHP及常用擴(kuò)展,並通過(guò)創(chuàng)建測(cè)試文件驗(yàn)證安裝是否成功。

我如何驗(yàn)證PHP中的用戶輸入以確保其符合某些標(biāo)準(zhǔn)? 我如何驗(yàn)證PHP中的用戶輸入以確保其符合某些標(biāo)準(zhǔn)? Jun 22, 2025 am 01:00 AM

TovalidateuserinputinPHP,usebuilt-invalidationfunctionslikefilter_var()andfilter_input(),applyregularexpressionsforcustomformatssuchasusernamesorphonenumbers,checkdatatypesfornumericvalueslikeageorprice,setlengthlimitsandtrimwhitespacetopreventlayout

如何使用session_destroy()在PHP中破壞會(huì)話? 如何使用session_destroy()在PHP中破壞會(huì)話? Jun 20, 2025 am 01:06 AM

要完全銷(xiāo)毀PHP中的會(huì)話,必須先調(diào)用session_start()啟動(dòng)會(huì)話,再調(diào)用session_destroy()刪除所有會(huì)話數(shù)據(jù)。 1.首先使用session_start()確保會(huì)話已啟動(dòng);2.然後調(diào)用session_destroy()清除會(huì)話數(shù)據(jù);3.可選但推薦:手動(dòng)unset$_SESSION數(shù)組以清除全局變量;4.同時(shí)刪除會(huì)話cookie,防止用戶保留會(huì)話狀態(tài);5.最後注意在銷(xiāo)毀後重定向用戶,並避免立即復(fù)用會(huì)話變量,否則需重新啟動(dòng)會(huì)話。這樣做能確保用戶徹底退出系統(tǒng),不留殘留信息。

什麼是php(serialize(),Unserialize())中的數(shù)據(jù)序列化? 什麼是php(serialize(),Unserialize())中的數(shù)據(jù)序列化? Jun 22, 2025 am 01:03 AM

thephpfunctionserize()andunSerialize()redustoconvertComplexdatStructDestoresToroStoroStoroSandaBackagagain.1.Serialize()

See all articles