欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

聊一聊關(guān)于php源碼中refcount的疑問

 更新時(shí)間:2022年11月03日 15:18:55   作者:church  
這篇文章主要給大家介紹了關(guān)于對php源碼中refcount的相關(guān)疑問,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

在瀏覽PHP源碼的時(shí)候,在眾多的*.stub.php中,發(fā)現(xiàn)了這樣的注釋,@refcount 1。

通過翻看build/gen_stub.php源碼,發(fā)現(xiàn)了在解析*.stub.php文件時(shí),關(guān)于返回信息的代碼。

<?php
class ReturnInfo {
    const REFCOUNT_0 = "0";
    const REFCOUNT_1 = "1";
    const REFCOUNT_N = "N";

    const REFCOUNTS = [
        self::REFCOUNT_0,
        self::REFCOUNT_1,
        self::REFCOUNT_N,
    ];

    //...
    
    private function setRefcount(?string $refcount): void
    {
        $type = $this->phpDocType ?? $this->type;
        $isScalarType = $type !== null && $type->isScalar();

        if ($refcount === null) {
            $this->refcount = $isScalarType ? self::REFCOUNT_0 : self::REFCOUNT_N;
            return;
        }

        if (!in_array($refcount, ReturnInfo::REFCOUNTS, true)) {
            throw new Exception("@refcount must have one of the following values: \"0\", \"1\", \"N\", $refcount given");
        }

        if ($isScalarType && $refcount !== self::REFCOUNT_0) {
            throw new Exception('A scalar return type of "' . $type->__toString() . '" must have a refcount of "' . self::REFCOUNT_0 . '"');
        }

        if (!$isScalarType && $refcount === self::REFCOUNT_0) {
            throw new Exception('A non-scalar return type of "' . $type->__toString() . '" cannot have a refcount of "' . self::REFCOUNT_0 . '"');
        }

        $this->refcount = $refcount;
    }

明顯,如果返回值類型是scalar,也就是標(biāo)量(基本數(shù)據(jù)類型,整型、浮點(diǎn)型、字符串等),那么refcount指定為0,否則為N。如果設(shè)置了注釋,那么以注釋為最高優(yōu)先級。

以函數(shù)ob_list_handlers為例:

/**
 * @return array<int, string>
 * @refcount 1
 */
function ob_list_handlers(): array {}

返回值是array,所以默認(rèn)的refcount應(yīng)該是N,但由于設(shè)置了注釋@refcount 1,所以返回值的引用計(jì)數(shù)被替換成1。

這些邏輯我能看懂,但設(shè)置返回值引用計(jì)數(shù)的目的是什么?我還是一頭霧水

我接著往下排查,發(fā)現(xiàn)通過返回值的引用計(jì)數(shù),在生成func_info的時(shí)候,會有些不同。如果返回值引用計(jì)數(shù)為1或N,則會用對應(yīng)的宏去初始化func_info結(jié)構(gòu)體。如果是0,則不進(jìn)入初始化列表。

以上的代碼邏輯依然可以在gen_stub.php中找到,1393行,getOptimizerInfo

public function getOptimizerInfo(): ?string {
        if ($this->isMethod()) {
            return null;
        }

        if ($this->alias !== null) {
            return null;
        }

        if ($this->return->refcount !== ReturnInfo::REFCOUNT_1 && $this->return->phpDocType === null) {
            return null;
        }

        $type = $this->return->phpDocType ?? $this->return->type;
        if ($type === null) {
            return null;
        }

        return "\tF" . $this->return->refcount . '("' . $this->name->__toString() . '", ' . $type->toOptimizerTypeMask() . "),\n";
    }

獲取函數(shù)原型的refcount,生成諸如F1()FN()的代碼,生成的頭文件位置在Zend/Optimizer/zend_func_infos.h。

static const func_info_t func_infos[] = {
    F1("zend_version", MAY_BE_STRING),
    FN("func_get_args", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ANY),
    F1("get_class_vars", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF),
    F1("get_class_methods", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("get_included_files", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    FN("set_error_handler", MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_OBJECT|MAY_BE_NULL),
    FN("set_exception_handler", MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_OBJECT|MAY_BE_NULL),
    F1("get_declared_classes", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("get_declared_traits", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("get_declared_interfaces", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("get_defined_functions", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ARRAY),
    F1("get_defined_vars", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF),
    F1("get_resource_type", MAY_BE_STRING),
    F1("get_loaded_extensions", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("get_defined_constants", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY),
    F1("debug_backtrace", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ARRAY),
    F1("get_extension_funcs", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE),
    F1("gc_status", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_FALSE|MAY_BE_ARRAY_OF_TRUE),
    F1("bcadd", MAY_BE_STRING),
    F1("bcsub", MAY_BE_STRING),
    F1("bcmul", MAY_BE_STRING),
    F1("bcdiv", MAY_BE_STRING),
    F1("bcmod", MAY_BE_STRING),
    F1("bcpowmod", MAY_BE_STRING),
    F1("bcpow", MAY_BE_STRING),
    F1("bcsqrt", MAY_BE_STRING),
    FN("bzopen", MAY_BE_RESOURCE|MAY_BE_FALSE),
    F1("bzerror", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("cal_from_jd", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_NULL),
    F1("cal_info", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY),
    F1("curl_copy_handle", MAY_BE_OBJECT|MAY_BE_FALSE),
    //...
};

再去看看F1FN的宏定義。

typedef struct _func_info_t {
    const char *name;
    unsigned    name_len;
    uint32_t    info;
    info_func_t info_func;
} func_info_t;

#define F0(name, info) \
    {name, sizeof(name)-1, (info), NULL}
#define F1(name, info) \
    {name, sizeof(name)-1, (MAY_BE_RC1 | (info)), NULL}
#define FN(name, info) \
    {name, sizeof(name)-1, (MAY_BE_RC1 | MAY_BE_RCN | (info)), NULL}
#define FC(name, callback) \
    {name, sizeof(name)-1, 0, callback}

僅僅是設(shè)置了不同的type mask,F1設(shè)置了MAY_BE_RC1,FN設(shè)置了MAY_BE_RCN | MAY_BE_RC1。

依然一頭霧水,但是通過目錄名,我依稀能猜出這跟性能優(yōu)化有關(guān),跟JIT有關(guān)系。我決定繼續(xù)追查下去,看看這些初始化后的結(jié)構(gòu)體在哪里使用過。

我們很清楚,設(shè)置位信息用|,那判斷有沒有設(shè)置肯定用&,全局搜索& MAY_BE_RCN,再看看哪些代碼跟優(yōu)化有關(guān),定位到了如下代碼,在zend_jit.c的530行:

#ifdef ZEND_JIT_USE_RC_INFERENCE
    /* Refcount may be increased by RETURN opcode */
    if ((info & MAY_BE_RC1) && !(info & MAY_BE_RCN)) {
        for (j = 0; j < ssa->cfg.blocks_count; j++) {
            if ((ssa->cfg.blocks[j].flags & ZEND_BB_REACHABLE) &&
                ssa->cfg.blocks[j].len > 0) {
                const zend_op *opline = op_array->opcodes + ssa->cfg.blocks[j].start + ssa->cfg.blocks[j].len - 1;

                if (opline->opcode == ZEND_RETURN) {
                    if (opline->op1_type == IS_CV && opline->op1.var == EX_NUM_TO_VAR(var)) {
                        info |= MAY_BE_RCN;
                        break;
                    }
                }
            }
        }
    }
#endif

如果返回值的引用計(jì)數(shù)是1,而不是N的時(shí)候,并且開啟了返回值引用計(jì)數(shù)推導(dǎo)功能,就走這段代碼。這段代碼又涉及到所謂SSA,靜態(tài)單賦值的編譯器設(shè)計(jì)方式。

在編譯器設(shè)計(jì)中,靜態(tài)單一賦值形式(通??s寫為SSA形式或簡稱SSA)是中間表示(IR)的屬性,它要求每個(gè)變量只分配一次,并且每個(gè)變量在使用之前定義。原始IR中的現(xiàn)有變量被拆分為版本,在教科書中,新變量通常由原始名稱用下標(biāo)表示,以便每次定義都有自己的版本。在SSA形式中,use-def鏈?zhǔn)秋@式的,每個(gè)包含一個(gè)元素。

所以上面的代碼就是判斷SSA的cfg(control flow graph控制流圖)的塊是不是可達(dá)的,如果可達(dá),執(zhí)行條件中的代碼。

還是不太通透,雖然能推斷出設(shè)置refcount跟優(yōu)化有關(guān),跟靜態(tài)單一賦值有關(guān),但在寫擴(kuò)展的時(shí)候,什么時(shí)候該用@refcount 1,還是不太清楚。

 總結(jié)

到此這篇關(guān)于php源碼中refcount疑問的文章就介紹到這了,更多相關(guān)php源碼中refcount內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 10個(gè)值得深思的PHP面試題

    10個(gè)值得深思的PHP面試題

    這篇文章主要為大家分享了值得深入思考的10個(gè)PHP面試問題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • php開發(fā)環(huán)境配置記錄

    php開發(fā)環(huán)境配置記錄

    我一般都是自己配置環(huán)境,為了方便在異地快速配置,總結(jié)一下,備忘.如果大家感覺麻煩可以一些php運(yùn)行環(huán)境軟件。例如phpnow等。
    2011-01-01
  • PHP開發(fā)實(shí)現(xiàn)快遞查詢功能詳解

    PHP開發(fā)實(shí)現(xiàn)快遞查詢功能詳解

    這篇文章主要介紹了PHP開發(fā)實(shí)現(xiàn)快遞查詢功能,結(jié)合實(shí)例形式分析了php使用快遞鳥查詢接口進(jìn)行快遞查詢的相關(guān)實(shí)現(xiàn)步驟與操作技巧,需要的朋友可以參考下
    2019-04-04
  • 利用PHP實(shí)現(xiàn)圖片等比例放大和縮小的方法詳解

    利用PHP實(shí)現(xiàn)圖片等比例放大和縮小的方法詳解

    本篇文章是對利用PHP實(shí)現(xiàn)圖片等比例放大和縮小的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • 實(shí)現(xiàn)PHP多線程異步請求的3種方法

    實(shí)現(xiàn)PHP多線程異步請求的3種方法

    實(shí)現(xiàn)PHP多線程異步請求的方法有很多,在本文整理了3種不多的常用方法,大家可以參考下
    2014-01-01
  • php pack與unpack 摸板字符字符含義

    php pack與unpack 摸板字符字符含義

    pack/unpack的摸板字符字符含義,需要的朋友可以參考下。
    2009-10-10
  • PHP實(shí)現(xiàn)基數(shù)排序的方法詳解

    PHP實(shí)現(xiàn)基數(shù)排序的方法詳解

    這篇文章主要介紹了PHP實(shí)現(xiàn)基數(shù)排序的方法,結(jié)合實(shí)例形式分析了基數(shù)排序的原理、實(shí)現(xiàn)方法與相關(guān)操作技巧,需要的朋友可以參考下
    2017-12-12
  • 利用擴(kuò)展的方式在PHP中使用Kafka的教程分享

    利用擴(kuò)展的方式在PHP中使用Kafka的教程分享

    這篇文章主要為大家詳細(xì)介紹了如何利用擴(kuò)展的方式實(shí)現(xiàn)在PHP中使用Kafka,具體包括擴(kuò)展安裝和這種方式的基本操作,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-05-05
  • PHP通過串口實(shí)現(xiàn)發(fā)送短信

    PHP通過串口實(shí)現(xiàn)發(fā)送短信

    本文給大家詳細(xì)介紹了,如何使用php通過串口來實(shí)現(xiàn)發(fā)送短信的思路以及具體的實(shí)現(xiàn)代碼,十分的實(shí)用,有需要的小伙伴可以參考下。
    2015-07-07
  • 一文解決PHP中生成隨機(jī)數(shù)遇到的重復(fù)問題

    一文解決PHP中生成隨機(jī)數(shù)遇到的重復(fù)問題

    項(xiàng)目開發(fā)中很多地方需要用到唯一編碼,比如說訂單、卡券、邀請碼等等,這些編號是需要嚴(yán)格保證唯一性的,因?yàn)槿绻到y(tǒng)中訂單的編號存在倆一模一樣的,那造成很多數(shù)據(jù)的錯(cuò)亂,所以本文給大家介紹了如何解決PHP中生成隨機(jī)數(shù)遇到的重復(fù)問,需要的朋友可以參考下
    2023-12-12

最新評論