24 August 2013

学习自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中, 即变量的跨域操作。