php 变量(下)
学习自TIPI,做个小结,内容从TIPI中选取
###常量
常量是在变量的zval结构的基础上添加了一些额外的元素,内部结构如下。
1
2
3
4
5
6
7
typedef struct _zend_constant {
zval value; /* zval结构,PHP内部变量的存储结构 */
int flags; /* 常量的标记如 CONST_PERSISTENT | CONST_CS | CONST_CT_SUBST*/
char *name; /* 常量名称 */
uint name_len;
int module_number; /* 模块号 */
} zend_constant;
flags值说明:
默认值为CONT_CS,表示大小写敏感 CONST_PERSISTENT表示常量要持久化 CONST_CT_SUBST在编译时可被替换,在PHP内核中这些常量包括:TRUE、FALSE、NULL、ZEND_THREAD_SAFE和ZEND_DEBUG_BUILD五个。
###标准常量的初始化
通过define()函数定义的常量的模块编号都是PHP_USER_CONSTANT,这表示是用户定义的常量。 除此之外我们在平时使用较多的常量:如错误报告级别E_ALL, E_WARNING等常量就有点不同了。 这些是PHP内置定义的常量,他们属于标准常量。
在Zend引擎启动后,会执行如下的标准常量注册操作,
php_module_startup() -> zend_startup() -> zend_register_standard_constants()
。
1
2
3
4
5
6
void zend_register_standard_constants(TSRMLS_D)
{
... // 若干常量以REGISTER_MAIN_LONG_CONSTANT设置,
REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS);
...
}
REGISTER_MAIN_LONG_CONSTANT()是一个宏,用于注册一个长整形数字的常量,因为C是强类型 语言,不同类型的数据等分别处理,以上的宏展开到下面这个函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
ZEND_API void zend_register_long_constant(const char *name, uint name_len,
long lval, int flags, int module_number TSRMLS_DC)
{
zend_constant c;
c.value.type = IS_LONG;
c.value.value.lval = lval;
c.flags = flags;
c.name = zend_strndup(name, name_len-1);
c.name_len = name_len;
c.module_number = module_number;
zend_register_constant(&c TSRMLS_CC);
}
代码很容易理解,前面看到注册内置常量都是用了CONST_PERSISTENT标志位,也就是说, 这些常量都是持久化常量。
###魔术常量
PHP提供了大量的预定义常量,有一些是内置的,也有一些是扩展提供的,只有在加载了这些扩展库时才会出现。
不过PHP中有七个魔术常量,他们的值其实是变化的,它们的值随着它们在代码中的位置改变而改变。 所以称他们为魔术常量。例如 LINE 的值就依赖于它在脚本中所处的行来决定。 这些特殊的常量不区分大小写,分别有:__LINE__,__FILE__,__DIR__,__FUNCTION____CLASS__,__METHOD__,__NAMESPACE__。
PHP内核会在词法解析时将这些常量的内容赋值进行替换,而不是在运行时进行分析。这些常量其实相当于一个占位符,在词法解析时这些占位符就被替换成实际的值。
###预定义变量
诸如$_GET,$_POST,$_SERVER,$_FILES等变量都是PHP的预定义变量,PHP是在脚本运行之前就将预定义变量加入到了符号表。
###静态变量
Zend为每个函数(准确的说是zend_op_array)分配了一个私有的符号表来保存该函数的静态变量。
###类型提示的实现
PHP中的类型提示功能只能用于参数为对象的提示,而无法用于为整数,字串,浮点等类型提示。在PHP5.1之后,PHP支持对数组的类型提示。
1
2
3
4
function array_print(Array $arr) {
print_r($arr);
}
array_print(1);
以上代码会在运行时产生错误报告。
1
2
3
4
function array_print(Array $arr = 1) {
print_r($arr);
}
array_print(array(1));
以上代码会在中间代码生成时产生错误报告,具体实现翻书吧。
###变量的作用域
PHP中的变量都保存在符号表中,对于全局变量和局部变量,分别存放在symbol_table和相对应的active_symbol_table.
变量的作用域是使用不同的符号表来实现的,于是顶层的全局变量在函数内部使用时, 需要先使用global语句来将变量“挪”到函数独立的*active_symbol_table中, 即变量的跨域操作。