php的常量

之前一直没看过php中是如何定义一个常量的,今天空闲的时候看了下,发现其机制也很简单

在php中定义常量 有define,和const两个方法

区别是define是个函数

const是个结构

define不能用于类中

可以用define 定义一个表达式,

const不能定义为一个表达式

<?php
const ABC="def";
echo ABC;
?>

const ABC="def"对应的opcode为 ZEND_DECLARE_CONST ,其实常说的opcode是zend_op这个结构体里的一个属性,叫opcode, 就是一个数字,只不过以宏的形式展现

static int ZEND_FASTCALL  ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE

    zval *name;
    zval *val;
    zend_constant c;

    SAVE_OPLINE();
    name  = opline->op1.zv;
    val   = opline->op2.zv;

    if ((Z_TYPE_P(val) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || Z_TYPE_P(val) == IS_CONSTANT_ARRAY) {
        ///
    } else {
        INIT_PZVAL_COPY(&c.value, val);
        zval_copy_ctor(&c.value);
    }
    c.flags = CONST_CS; /* non persistent, case sensetive */
    c.name = IS_INTERNED(Z_STRVAL_P(name)) ? Z_STRVAL_P(name) : zend_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name));
    c.name_len = Z_STRLEN_P(name)+1;
    c.module_number = PHP_USER_CONSTANT;

    if (zend_register_constant(&c TSRMLS_CC) == FAILURE) {
    }

    CHECK_EXCEPTION();
    ZEND_VM_NEXT_OPCODE();
}

最终放到的是EG(zend_constant)这个hashtable里

ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC)
{
    char *lowercase_name = NULL;
    char *name;
    int ret = SUCCESS;
    ulong chash = 0;


    if (!(c->flags & CONST_CS)) {
        /* keep in mind that c->name_len already contains the '' */
        lowercase_name = estrndup(c->name, c->name_len-1);
        zend_str_tolower(lowercase_name, c->name_len-1);
        lowercase_name = (char*)zend_new_interned_string(lowercase_name, c->name_len, 1 TSRMLS_CC);
        name = lowercase_name;
        chash = IS_INTERNED(lowercase_name) ? INTERNED_HASH(lowercase_name) : 0;
    } else {
        
    }
    if (chash == 0) {
        chash = zend_hash_func(name, c->name_len);
    }

    /* Check if the user is trying to define the internal pseudo constant name __COMPILER_HALT_OFFSET__ */
    if ((c->name_len == sizeof("__COMPILER_HALT_OFFSET__")
        && !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1))
        || zend_hash_quick_add(EG(zend_constants), name, c->name_len, chash, (void *) c, sizeof(zend_constant), NULL)==FAILURE) {
        
        ///
        ret = FAILURE;
    }
    if (lowercase_name && !IS_INTERNED(lowercase_name)) {
        efree(lowercase_name);
    }
    return ret;
}

echo ABC的时候, opcode是ZEND_FETCH_CONSTANT,下面的函数会把取出的数据赋值给  zend_op中的属性result, echo 时,再显示这个result的值

static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE

    SAVE_OPLINE();
    if (IS_UNUSED == IS_UNUSED) {
        zend_constant *c;
        zval *retval;

        if (CACHED_PTR(opline->op2.literal->cache_slot)) {
            c = CACHED_PTR(opline->op2.literal->cache_slot);
        } else if ((c = zend_quick_get_constant(opline->op2.literal + 1, opline->extended_value TSRMLS_CC)) == NULL) {
            if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
                char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\', Z_STRLEN_P(opline->op2.zv));
                if(!actual) {
                    actual = Z_STRVAL_P(opline->op2.zv);
                } else {
                    actual++;
                }
                /* non-qualified constant - allow text substitution */
                zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", actual, actual);
                ZVAL_STRINGL(&EX_T(opline->result.var).tmp_var, actual, Z_STRLEN_P(opline->op2.zv)-(actual - Z_STRVAL_P(opline->op2.zv)), 1);
                CHECK_EXCEPTION();
                ZEND_VM_NEXT_OPCODE();
            } else {
                zend_error_noreturn(E_ERROR, "Undefined constant '%s'", Z_STRVAL_P(opline->op2.zv));
            }
        } else {
            CACHE_PTR(opline->op2.literal->cache_slot, c);
        }
        retval = &EX_T(opline->result.var).tmp_var;
        ZVAL_COPY_VALUE(retval, &c->value);
        zval_copy_ctor(retval);
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
    }
}
原文地址:https://www.cnblogs.com/taek/p/6700892.html