成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

PHP源碼分析之等于操作符(==)

sushi / 1542人閱讀

摘要:中不同類型的變量進行弱類型比較時,有其語言本身比較特殊的規(guī)則。方法源碼如下操作數(shù)類型舉例結(jié)果將轉(zhuǎn)換為,進行數(shù)字或詞匯比較源碼說明結(jié)果將字符串和資源轉(zhuǎn)換成數(shù)字,按普通數(shù)學比較源碼說明其他各類型比較規(guī)則見于源碼

PHP 中不同類型的變量進行弱類型比較時,有其語言本身比較特殊的規(guī)則。本文就起比較規(guī)則,就其源碼角度進行解釋。

PHP-version:5.3

官方規(guī)則

參考: PHP.net

規(guī)則解釋

通過詞法分析/語法分析/利用vld查看opcode,我發(fā)現(xiàn) PHP 源碼中,比較操作符實現(xiàn)的核心方法是 compare_function,位于 Zend/zend_operators.c +1376

確定核心方法源碼位置 詞法分析


如上圖示,通過 Zend/zend_language_scanner.l +1201 詞法分析規(guī)則,得到 == 對應的 Token 為:T_IS_EQUAL

語法分析


Zend/zend_language_parser.y 搜索上一步得到的 Token 值,得到語法分析中調(diào)用生成 opcode 的方法為:zend_do_binary_op,同時看到 == 所對應的 opcodeZEND_IS_EQUAL

確定 zend 執(zhí)行時的函數(shù)

opcode 對應的調(diào)用函數(shù)實現(xiàn)于 Zend/zend_vm_execute.h 文件中,在此文件中搜索 ZEND_IS_EQUAL 得到如下的函數(shù)列表:

方法均以 ZEND_IS_EQUAL_SPEC 開頭,名字后綴受 == 兩個操作數(shù)的 zval 類型影響,具體的類型可以通過 vld 查看,如:

猜測是左操作數(shù)的類型 + 右操作數(shù)的類型。
以上圖為例,左操作數(shù)類型為 IS_CONST, 右操作數(shù)類型為 IS_CV,則對應的處理方法應該是:ZEND_IS_EQUAL_SPEC_CONST_CV_HANDLER
(注:這種確認 handler 的方法只是經(jīng)驗規(guī)則,還有待源碼驗證)

以上的推測正確與否,不影響我們接下來的判斷,因為我們發(fā)現(xiàn)這些方法都會調(diào)用同一個核心方法 compare_function,比較的規(guī)則就在這個方法中。通過看此方法源碼,比較規(guī)則一目了然。

compare_function 方法源碼如下:

ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
{
    int ret;
    int converted = 0;
    zval op1_copy, op2_copy;
    zval *op_free;

    while (1) {
        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
            case TYPE_PAIR(IS_LONG, IS_LONG):
                ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)compare_objects(op1, op2 TSRMLS_CC));
                    return SUCCESS;
                }
                /* break missing intentionally */

            default:
                if (Z_TYPE_P(op1) == IS_OBJECT) {
                    if (Z_OBJ_HT_P(op1)->get) {
                        op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
                        zend_free_obj_get_result(op_free TSRMLS_CC);
                        return ret;
                    } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
                        ALLOC_INIT_ZVAL(op_free);
                        if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {
                            ZVAL_LONG(result, 1);
                            zend_free_obj_get_result(op_free TSRMLS_CC);
                            return SUCCESS;
                        }
                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
                        zend_free_obj_get_result(op_free TSRMLS_CC);
                        return ret;
                    }
                }
                if (Z_TYPE_P(op2) == IS_OBJECT) {
                    if (Z_OBJ_HT_P(op2)->get) {
                        op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC);
                        ret = compare_function(result, op1, op_free TSRMLS_CC);
                        zend_free_obj_get_result(op_free TSRMLS_CC);
                        return ret;
                    } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
                        ALLOC_INIT_ZVAL(op_free);
                        if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) {
                            ZVAL_LONG(result, -1);
                            zend_free_obj_get_result(op_free TSRMLS_CC);
                            return SUCCESS;
                        }
                        ret = compare_function(result, op1, op_free TSRMLS_CC);
                        zend_free_obj_get_result(op_free TSRMLS_CC);
                        return ret;
                    } else if (Z_TYPE_P(op1) == IS_OBJECT) {
                        ZVAL_LONG(result, 1);
                        return SUCCESS;
                    }
                }
                if (!converted) {
                    if (Z_TYPE_P(op1) == IS_NULL) {
                        zendi_convert_to_boolean(op2, op2_copy, result);
                        ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
                        return SUCCESS;
                    } else if (Z_TYPE_P(op2) == IS_NULL) {
                        zendi_convert_to_boolean(op1, op1_copy, result);
                        ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
                        return SUCCESS;
                    } else if (Z_TYPE_P(op1) == IS_BOOL) {
                        zendi_convert_to_boolean(op2, op2_copy, result);
                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
                        return SUCCESS;
                    } else if (Z_TYPE_P(op2) == IS_BOOL) {
                        zendi_convert_to_boolean(op1, op1_copy, result);
                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
                        return SUCCESS;
                    } else {
                        zendi_convert_scalar_to_number(op1, op1_copy, result);
                        zendi_convert_scalar_to_number(op2, op2_copy, result);
                        converted = 1;
                    }
                } else if (Z_TYPE_P(op1)==IS_ARRAY) {
                    ZVAL_LONG(result, 1);
                    return SUCCESS;
                } else if (Z_TYPE_P(op2)==IS_ARRAY) {
                    ZVAL_LONG(result, -1);
                    return SUCCESS;
                } else if (Z_TYPE_P(op1)==IS_OBJECT) {
                    ZVAL_LONG(result, 1);
                    return SUCCESS;
                } else if (Z_TYPE_P(op2)==IS_OBJECT) {
                    ZVAL_LONG(result, -1);
                    return SUCCESS;
                } else {
                    ZVAL_LONG(result, 0);
                    return FAILURE;
                }
        }
    }
}
操作數(shù)類型舉例 null

結(jié)果:將 NULL 轉(zhuǎn)換為 "",進行數(shù)字或詞匯比較

源碼說明:

array

結(jié)果:將字符串和資源轉(zhuǎn)換成數(shù)字,按普通數(shù)學比較

源碼說明:

其他各類型比較規(guī)則見于 compare_function 源碼

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/30689.html

相關文章

  • PHP7源碼分析PHP7到底有多快,基準測試與特性分析告訴你

    摘要:我們修改上面代碼,再來看下返回值類型限制的情況運行結(jié)果這段代碼我們額外聲明了返回值的類型為型。對函數(shù)返回值的聲明做了擴充,可以定義其返回值為,無論是否開啟嚴格模式,只要函數(shù)中有以外的其他語句都會報錯。 順風車運營研發(fā)團隊 王坤 發(fā)表至21CTO公眾號(https://mp.weixin.qq.com/s/ph...) showImg(https://segmentfault.c...

    Towers 評論0 收藏0
  • 后端ing

    摘要:當活動線程核心線程非核心線程達到這個數(shù)值后,后續(xù)任務將會根據(jù)來進行拒絕策略處理。線程池工作原則當線程池中線程數(shù)量小于則創(chuàng)建線程,并處理請求。當線程池中的數(shù)量等于最大線程數(shù)時默默丟棄不能執(zhí)行的新加任務,不報任何異常。 spring-cache使用記錄 spring-cache的使用記錄,坑點記錄以及采用的解決方案 深入分析 java 線程池的實現(xiàn)原理 在這篇文章中,作者有條不紊的將 ja...

    roadtogeek 評論0 收藏0
  • [PHP源碼閱讀]array_push和array_unshift函數(shù)

    摘要:對于函數(shù),實現(xiàn)時新建一個哈希表,將需要插入的數(shù)據(jù)先插入到中,然后再把原來的數(shù)組數(shù)據(jù)寫入到中,這樣實現(xiàn)在數(shù)組前面插入數(shù)據(jù)元素的功能。這次閱讀源碼過程中,同時也研究了中的哈希表數(shù)據(jù)結(jié)構(gòu)及一些,也給自己補充了一些哈希表的知識。 在PHP中,在數(shù)組中添加元素也是一種很常用的操作,分別有在數(shù)組尾部和頭部添加元素,看看PHP內(nèi)部是如何實現(xiàn)數(shù)組插入的操作。 我在github有對PHP源碼更詳細的注解...

    HackerShell 評論0 收藏0
  • Codeigniter 4.0-dev 版源碼學習筆記七—— View 視圖

    摘要:行處理視圖文件名后綴。結(jié)語從源碼上看,使用了原始作為模版機制使得視圖邏輯非常簡單。無非也就是把視圖進來,用輸出緩沖把執(zhí)行結(jié)果拿到即可。此文可以轉(zhuǎn)載,但轉(zhuǎn)載前需要發(fā)郵件到進行溝通,未溝通的均視作侵權(quán)。 前言 CI 的 View 沒有像 Laravel 等一些流行框架一樣設計的那么重,有自己的一套模版機制,CI 一直采用純天然的 PHP 模板形式,純天然的好處是不用再學習一套模板語言了,缺...

    LiangJ 評論0 收藏0
  • JavaScript專題解讀 v8 排序源碼

    摘要:插入排序是穩(wěn)定的算法。所以準確的說,當數(shù)組長度大于的時候,采用了快速排序和插入排序的混合排序方法。在對數(shù)組進行了一次快速排序后,然后對兩個子集分別進行了插入排序,最終修改數(shù)組為正確排序后的數(shù)組。 JavaScript 專題系列第二十篇,也是最后一篇,解讀 v8 排序源碼 前言 v8 是 Chrome 的 JavaScript 引擎,其中關于數(shù)組的排序完全采用了 JavaScript 實...

    princekin 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<