最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2013年11月04日 14:36:54   作者:  
今天閱讀php源碼,發(fā)現(xiàn)define的第二個參數(shù)其實也可以是一個對象,我們來看看如何使用。
看手冊說define定義的常量只允許:
僅允許標(biāo)量和 null。標(biāo)量的類型是 integer, float,string 或者 boolean。 也能夠定義常量值的類型為 resource ,但并不推薦這么做,可能會導(dǎo)致未知狀況的發(fā)生。
今天閱讀php源碼,發(fā)現(xiàn)define的第二個參數(shù)其實也可以是一個對象。
先貼一段示例:
復(fù)制代碼 代碼如下:

class A {
    public function __toString() {
        return 'bar';
    }
}

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

接著來看看php中的define究竟是如何實現(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個參數(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類常量,則報錯
    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;

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

注意以repeat開始的一段循環(huán),還用到了goto語句T_T
這段代碼的作用為:
對于int,float,string,bool,resource,null,則實際定義的常量時直接使用這些值
對于object,則需要將object轉(zhuǎn)成上述6個類型之一(如果轉(zhuǎn)型之后依然是object,則繼續(xù)轉(zhuǎn)型)
如何將object成6個類型之一呢?從代碼上看有2種手段:
復(fù)制代碼 代碼如下:

if (Z_OBJ_HT_P(val)->get) {
    val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);
    goto repeat;
}
// __toString()方法會在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是一個包含很多函數(shù)指針的結(jié)構(gòu)體,具體定義參見_zend_object_handlers 。該結(jié)構(gòu)體中的函數(shù)指針均用于操作object,比如讀取/修改對象屬性、獲取/調(diào)用對象方法等等…get和cast_object也是其中之一。
對于一般的對象,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;
}

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

相關(guān)文章

  • 驗證坐標(biāo)在某坐標(biāo)區(qū)域內(nèi)php代碼

    驗證坐標(biāo)在某坐標(biāo)區(qū)域內(nèi)php代碼

    這篇文章主要為大家詳細(xì)介紹了驗證坐標(biāo)在某片坐標(biāo)區(qū)域內(nèi)php代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • PHP利用Socket獲取網(wǎng)站的SSL證書與公鑰

    PHP利用Socket獲取網(wǎng)站的SSL證書與公鑰

    這篇文章主要給大家介紹了PHP利用Socket獲取網(wǎng)站的SSL證書與公鑰的相關(guān)資料,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。
    2017-06-06
  • FCKeditor添加自定義按鈕

    FCKeditor添加自定義按鈕

    我想在FCKeditor 中的工具欄上添加一個按鈕,在哪個配置文件中修改?答案很簡單。
    2008-03-03
  • 詳解PHP匿名函數(shù)與注意事項

    詳解PHP匿名函數(shù)與注意事項

    這篇文章主要為大家詳細(xì)介紹了詳解PHP匿名函數(shù)與注意事項,匿名函數(shù)是PHP5.3引進(jìn)來的,想要學(xué)習(xí)匿名函數(shù)的朋友可以參考一下
    2016-03-03
  • ThinkPHP5 驗證器的具體使用

    ThinkPHP5 驗證器的具體使用

    這篇文章主要介紹了ThinkPHP5 驗證器的具體使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • 如何解決php domdocument找不到的問題

    如何解決php domdocument找不到的問題

    在本篇文章里小編給大家整理的是一篇關(guān)于php domdocument找不到的解決辦法,有需要的朋友們可以跟著學(xué)習(xí)參考下。
    2021-07-07
  • php操作SVN版本服務(wù)器類代碼

    php操作SVN版本服務(wù)器類代碼

    使用PHP完成SVN的操作,包括復(fù)制,查看列表,刪除,移動,創(chuàng)建目錄,查看diff,更新,合并,提交,獲取狀態(tài),獲取commit log,獲取當(dāng)前版本號操作。在svn 1.6.11版本中測試通過
    2011-11-11
  • php5數(shù)字型字符串加解密代碼

    php5數(shù)字型字符串加解密代碼

    對應(yīng)awk版加解密程序的PHP實現(xiàn)代碼
    2008-04-04
  • php實現(xiàn)的證件照換底色功能示例【人像摳圖/換背景圖】

    php實現(xiàn)的證件照換底色功能示例【人像摳圖/換背景圖】

    這篇文章主要介紹了php實現(xiàn)的證件照換底色功能,結(jié)合實例形式分析了php實人像摳圖與換背景圖相關(guān)操作技巧,需要的朋友可以參考下
    2020-05-05
  • php獲取linux命令結(jié)果的實例

    php獲取linux命令結(jié)果的實例

    下面小編就為大家?guī)硪黄猵hp獲取linux命令結(jié)果的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03

最新評論

梁平县| 西乌| 广饶县| 乌鲁木齐县| 临城县| 思南县| 濮阳市| 永嘉县| 古浪县| 麻江县| 彭州市| 普洱| 双流县| 亚东县| 湘乡市| 光山县| 临夏县| 友谊县| 鹤峰县| 武安市| 修水县| 长白| 霞浦县| 额敏县| 日照市| 景东| 体育| 德兴市| 凤凰县| 岗巴县| 桂林市| 额敏县| 思茅市| 错那县| 和静县| 北票市| 进贤县| 富川| 微博| 苏尼特右旗| 保德县|