91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在php中使用define的第二個參數

發布時間:2021-03-05 15:03:46 來源:億速云 閱讀:156 作者:Leah 欄目:開發技術

如何在php中使用define的第二個參數?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

php有什么用

php是一個嵌套的縮寫名稱,是英文超級文本預處理語言,它的語法混合了C、Java、Perl以及php自創新的語法,主要用來做網站開發,許多小型網站都用php開發,因為php是開源的,從而使得php經久不衰。

define定義的常量只允許:
僅允許標量和 null。標量的類型是 integer, float,string 或者 boolean。 也能夠定義常量值的類型為 resource ,但并不推薦這么做,可能會導致未知狀況的發生。
今天閱讀php源碼,發現define的第二個參數其實也可以是一個對象。
先貼一段示例:

復制代碼 代碼如下:


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

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


接著來看看php中的define究竟是如何實現的:

復制代碼 代碼如下:


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個參數,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;
    }

    // 構建常量
    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開始的一段循環,還用到了goto語句T_T
這段代碼的作用為:
對于int,float,string,bool,resource,null,則實際定義的常量時直接使用這些值
對于object,則需要將object轉成上述6個類型之一(如果轉型之后依然是object,則繼續轉型)
如何將object成6個類型之一呢?從代碼上看有2種手段:

復制代碼 代碼如下:


if (Z_OBJ_HT_P(val)->get) {
    val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);
    goto repeat;
}
// __toString()方法會在cast_object中被調用
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是一個包含很多函數指針的結構體,具體定義參見_zend_object_handlers 。該結構體中的函數指針均用于操作object,比如讀取/修改對象屬性、獲取/調用對象方法等等…get和cast_object也是其中之一。
對于一般的對象,php提供了標準的cast_object函數zend_std_cast_object_tostring,代碼位于php-src/zend/zend-object-handlers.c中:

復制代碼 代碼如下:


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,則嘗試調用
            if (ce->__tostring &&
                (zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) {
                ……

            }
            return FAILURE;
        ……
    }
    return FAILURE;
}


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

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

新宾| 丽江市| 佛山市| 阳原县| 库车县| 永德县| 廉江市| 赣榆县| 海城市| 丁青县| 凤翔县| 竹山县| 斗六市| 丹阳市| 石阡县| 阿拉善右旗| 灯塔市| 桓台县| 石渠县| 吴忠市| 东乌| 疏勒县| 房产| 都安| 旬阳县| 德格县| 田林县| 龙门县| 临沂市| 浦城县| 车致| 乐至县| 洪泽县| 鄂伦春自治旗| 宿松县| 正阳县| 元氏县| 婺源县| 玛纳斯县| 云霄县| 犍为县|