|
在应用中经常使用define来定义一些常用的参数信息,来增加程序的可读性和可靠性。
在PHP中,常量的名字是一个简单的标识符,执行周期中不能改变,并且默认情况下是大小写敏感的。通常常量总是大写的。
注:define中的第三个参数可以设置是否常量名大小写敏感
一、常量的内部结构
typedef struct _zend_constant {
zval value; /* zval结构,PHP内部变量的存储结构 */
int flags; /* 常量的标记如 CONST_PERSISTENT | CONST_CS */
char *name; /* 常量名称 */
uint name_len; /* 常量名称字符长度 */
int module_number; /* 模块号 */
} zend_constant;
二、PHP中定义常量
<?php
define('DATABASE', 'MYSQL');
define('DATABASE_USER', 'ROOT');
define('DATABASE_PASSWORD', 'PASSWORD');
三、分析opcode
# php -dvld.active=1 index.php
打印出opchode,如下图
注,查看opcode扩展VLD安装可以阅读 《通过VLD扩展分析PHP opcode》
这里介绍出现的了三条指令,SEND_VAL、DO_FCALL、RETURN
SEND_VAL:传递参数的固定值,操作码65
RETURN:从函数中返回结果,操作码62
DO_FCALL:调用函数,操作码60
更多指令说明:http://php.net/manual/en/internals2.opcodes.list.php
四、通过ZEND VM执行opcode
void zif_define(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used )
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;//PHP中常量对应的结构体变量
/*
* sz|b function define(string, zval [, boolean])
* 这个参数表示定义接收的参数,s为字符串,z为zval,b为boolean
* */
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;
}
/* class constant, check if there is name and make sure class is valid & exists */
if (zend_memnstr(name, "::", sizeof("::") - 1, name + name_len)) {
zend_error(E_WARNING, "Class constants cannot be defined or redefined");
RETURN_FALSE;
}
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;
//上面,允许integer, float,string 或者 boolean和 null
case IS_OBJECT:
/* 如果传入的是对象, 通过判断是否定义__tostring()魔术方法,重新设置val值
* 可以看出,define已经接受对象作为参数,前提条件是定义了__tostring(),并且返回的值也是integer, float,string 或者 boolean和 null
* 此时,这里的版本是php5.3.8
* */
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;
}
} |
|
|