天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

php define的第二個(gè)參數(shù)使用方法

看手冊(cè)說define定義的常量只允許:
僅允許標(biāo)量和 null。標(biāo)量的類型是 integer, float,string 或者 boolean。 也能夠定義常量值的類型為 resource ,但并不推薦這么做,可能會(huì)導(dǎo)致未知狀況的發(fā)生。
今天閱讀php源碼,發(fā)現(xiàn)define的第二個(gè)參數(shù)其實(shí)也可以是一個(gè)對(duì)象。
先貼一段示例:
復(fù)制代碼 代碼如下:
class A {
    public function __toString() {
        return 'bar';
    }
}

$a = new A();
define('foo', $a);
echo foo;
// 輸出bar

接著來看看php中的define究竟是如何實(shí)現(xiàn)的:
復(fù)制代碼 代碼如下:
ZEND_FUNCTION(define)
{
    char *name;
    int name_len;
    zval *val;
    zval *val_free = NULL;
    zend_bool non_cs = 0;
    int case_sensitive = CONST_CS;
    zend_constant c;

    // 接收3個(gè)參數(shù),string,zval,bool
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) {
        return;
    }

    // 是否大小寫敏感
    if(non_cs) {
        case_sensitive = 0;
    }

    // 如果define類常量,則報(bào)錯(cuò)
    if (zend_memnstr(name, "::", sizeof("::") - 1, name + name_len)) {
        zend_error(E_WARNING, "Class constants cannot be defined or redefined");
        RETURN_FALSE;
    }

    // 獲取真正的值,用val保存
repeat:
    switch (Z_TYPE_P(val)) {
        case IS_LONG:
        case IS_DOUBLE:
        case IS_STRING:
        case IS_BOOL:
        case IS_RESOURCE:
        case IS_NULL:
            break;
        case IS_OBJECT:
            if (!val_free) {
                if (Z_OBJ_HT_P(val)->get) {
                    val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);
                    goto repeat;
                } else if (Z_OBJ_HT_P(val)->cast_object) {
                    ALLOC_INIT_ZVAL(val_free);
                    if (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == SUCCESS) {
                        val = val_free;
                        break;
                    }
                }
            }
            /* no break */
        default:
            zend_error(E_WARNING,"Constants may only evaluate to Scalar values");
            if (val_free) {
                zval_ptr_dtor(&val_free);
            }
            RETURN_FALSE;
    }

    // 構(gòu)建常量
    c.value = *val;
    zval_copy_ctor(&c.value);
    if (val_free) {
        zval_ptr_dtor(&val_free);
    }
    c.flags = case_sensitive; /* non persistent */
    c.name = zend_strndup(name, name_len);
    c.name_len = name_len+1;
    c.module_number = php_USER_CONSTANT;

    // 注冊(cè)常量
    if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {
        RETURN_TRUE;
    } else {
        RETURN_FALSE;
    }
}

注意以repeat開始的一段循環(huán),還用到了goto語句T_T
這段代碼的作用為:
對(duì)于int,float,string,bool,resource,null,則實(shí)際定義的常量時(shí)直接使用這些值
對(duì)于object,則需要將object轉(zhuǎn)成上述6個(gè)類型之一(如果轉(zhuǎn)型之后依然是object,則繼續(xù)轉(zhuǎn)型)
如何將object成6個(gè)類型之一呢?從代碼上看有2種手段:
復(fù)制代碼 代碼如下:
if (Z_OBJ_HT_P(val)->get) {
    val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);
    goto repeat;
}
// __toString()方法會(huì)在cast_object中被調(diào)用
else if (Z_OBJ_HT_P(val)->cast_object) {
    ALLOC_INIT_ZVAL(val_free);
    if (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == SUCCESS)
    {
        val = val_free;
        break;
    }
}

1,Z_OBJ_HT_P(val)->get ,宏展開之后為(*val).value.obj.handlers->get
2,Z_OBJ_HT_P(val)->cast_object,宏展開之后為(*val).value.obj.handlers->cast_object
handlers是一個(gè)包含很多函數(shù)指針的結(jié)構(gòu)體,具體定義參見_zend_object_handlers 。該結(jié)構(gòu)體中的函數(shù)指針均用于操作object,比如讀取/修改對(duì)象屬性、獲取/調(diào)用對(duì)象方法等等…get和cast_object也是其中之一。
對(duì)于一般的對(duì)象,php提供了標(biāo)準(zhǔn)的cast_object函數(shù)zend_std_cast_object_tostring,代碼位于php-src/zend/zend-object-handlers.c中:
復(fù)制代碼 代碼如下:
ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */
{
    zval *retval;
    zend_class_entry *ce;

    switch (type) {
        case IS_STRING:
            ce = Z_OBJCE_P(readobj);

            // 如果用戶的class中定義了__toString,則嘗試調(diào)用
            if (ce->__tostring &&
                (zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) {
                ……

            }
            return FAILURE;
        ……
    }
    return FAILURE;
}

從上述具體實(shí)現(xiàn)來看,默認(rèn)的cast_object就是去尋找class中的__tostring方法然后調(diào)用…
回到剛開始的例子,define(‘foo', $a) ,由于$a是A的實(shí)例,并且class A中定義了__toString,因此實(shí)際上foo常量就等于toString的返回值bar。

php技術(shù)php define的第二個(gè)參數(shù)使用方法,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 99国产精品久久 | 1000视频在线播放 | 高清观看ZSHH96的视频素材 | 国产老头与老太hd | 长泽梓黑人初解禁bdd07 | 黄色大片aa| yellow在线观看免费直播 | 热99re久久精品国产首页 | 久久国产精品自线拍免费 | 亚洲三区视频 | 男人插女人动态图 | 蜜芽在线播放免费人成日韩视频 | 亚洲h视频在线观看 | 欧美午夜精品一区区电影 | 欧美一级做a爰片免费 | 成人公开免费视频 | 日本欧美久久久久免费播放网 | 第一次处破女完整版电影 | 日日操夜夜摸 | 美女脱了内裤张开腿让男人桶到爽 | 日本精品久久久久中文字幕 | 果冻传媒视频在线观看完整版免费 | 日本一二三区视频在线 | 解开美女胸衣2破解版 | 欧洲亚洲精品A片久久99果冻 | 亚洲H成年动漫在线观看不卡 | 99视频国产热精品视频 | 国产精品福利片 | 午夜国产理论 | 亚洲国产高清福利视频 | 最近中文字幕在线中文高清版 | 91视频18| 亚洲视频在线免费观看 | 精品视频在线一区 | 午夜射精日本三级 | 全黄h全肉短篇禁乱np | 色婷婷国产精品视频一区二区 | 久久视频这里只精品6国产 久久视频在线视频观品15 | 如懿传免费观看在线全集 | 桃花论坛POWERED2019 | 免费在线伦理片 |