🌚

PHP常量的实现和操作

Posted at — May 07, 2015
#PHP #源码

存储结构

常量存储在哈希表EG(zend_constants)中。

常量的结构定义为:

1
2
3
4
5
6
7
typedef struct _zend_constant {
	zval value;
	int flags;
	char *name;
	uint name_len;
	int module_number;
} zend_constant;

value是常量的值,是一个zval。name是常量名。module_number是模块被加载时,PHP内核在MINIT和RINIT方法的原型里默认传递的一个值,作为模块清理时的线索,在注册常量的接口里直接传递即可。

flags是常量的标识或标识组合:

CONST_CS表示常量名对大小写敏感,对应PHP函数define()的第三个参数,TRUE、FALSE、NULL这些常量名对大小写是不敏感的。CONST_PERSISTENT表示常量在请求结束后被保存,只在PHP进程结束时才销毁,一般在MINIT中定义的常量应该指定此参数,RINIT中定义的不指定。CONST_CT_SUBST表示在编译时可替换,TRUE、FALSE、NULL、ZEND_THREAD_SAFE、ZEND_DEBUG_BUILD属于此类。

常量的声明

常量的声明方法有两种,简单的使用宏函数族REGISTER_*_CONSTANT():

REGISTER_NULL_CONSTANT(name, flags) REGISTER_BOOL_CONSTANT(name, bval, flags) REGISTER_LONG_CONSTANT(name, lval, flags) REGISTER_DOUBLE_CONSTANT(name, dval, flags) REGISTER_STRING_CONSTANT(name, str, flags) REGISTER_STRINGL_CONSTANT(name, str, len, flags)

由于不需指定常量名长度,所以name参数应直接使用字符串,而不是char*。

如需使用变量作为name参数,使用zend_register_*_constant()函数族,并指定变量名长度(sizeof(name))。上面的宏函数其实是对这族函数的封装。

void zend_register_long_constant(char *name, uint name_len, long lval, int flags, int module_number TSRMLS_DC) void zend_register_double_constant(char *name, uint name_len, double dval, int flags, int module_number TSRMLS_DC) void zend_register_bool_constant(const char *name, uint name_len, zend_bool bval, int flags, int module_number TSRMLS_DC) void zend_register_string_constant(char *name, uint name_len, char *strval, int flags, int module_number TSRMLS_DC) void zend_register_stringl_constant(char *name, uint name_len, char *strval, uint strlen, int flags, int module_number TSRMLS_DC)

除此之外,还有REGISTER_MAIN_*_CONSTANT和REGISTER_NS_*_CONSTANT两组宏函数。前者用于定义像E_ERROR这样的PHP标准常量,后者定义有命令空间的常量。

define()和const

魔术常量

__LINE__
__FILE__
__DIR__
__FUNCTION__
__CLASS__
__METHOD__
__NAMESPACE__

魔术常量是在编译时(具体地说是词法分析时,见Zend/zend_language_scanner.l)被替换,确切地说,这些不是真正意义上的常量,只是个模板占位符。