PHP内核介绍及扩展开发指南——Extensions 的编写:访问PHP变量

2012-11-28 12:27 阅读 620 次 评论关闭

一、基础知识

PHP内核介绍及扩展开发指南——基础知识:PHP变量的存储

PHP内核介绍及扩展开发指南——基础知识:HashTable结构

二、Extensions 的编写

PHP内核介绍及扩展开发指南——Extensions 的编写:Hello World

PHP内核介绍及扩展开发指南——Extensions 的编写:使用参数

PHP内核介绍及扩展开发指南——Extensions 的编写:返回值

PHP内核介绍及扩展开发指南——Extensions 的编写:启动和终止函数、调用PHP函数

2.6    访问PHP变量

2.6.1   设置

1.2.3节提到Zend使用HashTable来存储全局和局部变量符号,因此访问PHP变量,其实就是操作HashTable。当然,我们不需要手工去做,Zend提供了一组宏完成这些工作。

PHP变量的创建共有三步,首先需要创建一个zval结构,可使用如下的宏:

MAKE_STD_ZVAL(zval*)

这个宏先调用emalloc分配一块zval,然后将其refcount设为1、is_ref设为0。

之后就是设置zval的值,同样,我们不需要直接操作zval的成员,Zend已经提供了如下的宏:

Macro

Description
ZVAL_RESOURCE(zval*, resource) resource
ZVAL_BOOL(zval*, bool) boolean
ZVAL_FALSE(zval*) false
ZVAL_TRUE(zval*) true
ZVAL_NULL(zval*) NULL
ZVAL_LONG(zval*, long) long
ZVAL_DOUBLE(zval*, double) double
ZVAL_STRING(zval*, string, duplicate) string必须是C串,因为Zend将调用strlen();duplicate表示是否将传入的C串复制一份再赋给zval,如果传入的C串不是用Zend例程分配的,应该指定该值
ZVAL_STRINGL(zval*, string, length, duplicate) 指定字符串长度,而不是使用strlen()
ZVAL_EMPTY_STRING(zval*) 空字符串

 

可能你会发现,这个表格和2.3节里面的返回值宏表格很相似,不错,返回值宏就是直接调用的ZVAL_xxx。

既然有了zval,下面把它添加到变量符号表里就可以了,可以使用如下的一组宏:

 

ZEND_SET_SYMBOL(symtable, name, var)

ZEND_SET_GLOBAL_VAR(name, var)

symtable用来指定你想插入的符号表,一般使用EG(active_symbol_table),表示访问当前调用者的活动符号表。如果想强制访问全局符号表,可以用&EG(symbol_table),这也正是ZEND_SET_GLOBAL_VAR(name, var)所做的。这两个宏的最终效果和执行PHP赋值语句name = var完全一样。

如果只是访问全局变量,可以使用单个宏代替上述三步:

 

SET_VAR_STRING(name, value)

SET_VAR_STRINGL(name, value, length)

SET_VAR_LONG(name, value)

SET_VAR_DOUBLE(name, value)

上述宏分别用于创建全局的string、long和double变量,它们在内部执行了以上三步,当然,最后调用的是ZEND_SET_GLOBAL_VAR宏。

2.2.2   获取

如果想获取已有的PHP变量,则只能直接访问HashTable,Zend并没有提供相应的操作:

 

int zend_hash_find(

HashTable *ht,

char *arKey, uint nKeyLength,

void **pData)

这个函数从HashTable中查找元素,pData用于获取结果值,Bucket.pData将被放到这里(如果找到的话)。函数成功则返回SUCCESS,否则返回FAILURE。

下面是个示例:

 

zval **ppzval; // Bucket.pData里存放的是zval**

if(zend_hash_find(EG(active_symbol_table),"var", 4,

(void**)&ppzval) == SUCCESS)

printf("var.refcount = %d\n", (*p)->refcount);

    else

        printf("Not Found\n");

这段代码从活动符号表中查找名为var的变量,需要注意的是nKeyLength是4,必须包括结尾的0。

获得变量后,拿来读是没有问题的,但是写操作就应该小心对待了。只有当refcount为1或者is_ref为1,才可以写入;否则应该进行zval分离,具体参见2.2.3节。

2.2.3   常量

PHP常量的内部定义如下:

 

typedef struct _zend_constant {

       zval value;

       int flags;

       char *name;

       uint name_len;

       int module_number;

} zend_constant;

常量的值依然使用zval存储,但这里的zval是私有的,不会和其他变量或常量共享,其refcount和is_ref被忽略。module_number是模块号,在启动函数中可以获取该值(参见2.4),当模块被卸载时,Zend会使用模块号查找和删除所有该模块注册的常量。如果希望在模块被卸载后,常量依然有效,可以将module_number设为0。另一个注意点是,name_len需要包含结尾的0。

flags值可以是如下两个,可以使用”|”联用:

flag

意义

CONST_CS

常量名大小写敏感

CONST_PERSISTENT

持久常量,在创建常量的页面执行结束后,常量依然有效(*)

 

 

 

所有常量都被放在EG(zend_constants)这张HashTable里,其key是常量名称,value是zend_constant,注意不是zend_constant*,因此HashTable会复制一份zend_constant作为value。

获取一个常量非常简单,只要传递常量名和接受常量值的zval:

 

int zend_get_constant(char *name, uint name_len, zval *result

       TSRMLS_DC);

设置常量稍微复杂一点,需要先填写一个zend_constant结构,要注意的是,常量只能是long、double和string。然后使用如下函数将其加入常量表:

int zend_register_constant(zend_constant *c TSRMLS_DC);

同时,Zend也为我们提供了如下的宏,可以直接创建常量:

 

REGISTER_LONG_CONSTANT(name, value, flags)REGISTER_MAIN_LONG_CONSTANT(name, value, flags)
REGISTER_DOUBLE_CONSTANT(name, value, flags)REGISTER_MAIN_DOUBLE_CONSTANT(name, value, flags)
REGISTER_STRING_CONSTANT(name, value, flags)REGISTER_MAIN_STRING_CONSTANT(name, value, flags)
REGISTER_STRINGL_CONSTANT(name, value, length, flags)REGISTER_MAIN_STRINGL_CONSTANT(name, value, length, flags)

上述宏的MAIN版本用于创建module_number为0的宏,在模块被卸载后,常量依然有效。而非MAIN版本则假设存在一个名为module_number的int变量,并拿来给zend_constant.module_number赋值,可见这组宏原本就是为在模块启动函数里调用而设计的。另外,当创建string型常量时,Zend也会dup一份字符串,因此可以直接使用C串指定常量值。

最后需要指出的是,上述函数和宏都无法改变已有的常量,如果发现已经存在同名常量,则函数失败。如果想修改的话,只能通过HashTable操作。

下载专辑 

PHP内核介绍及扩展开发指南.doc

 

编写 PHP Extension

zhangdongjin@baidu.com

版权声明:本文著作权归原作者所有,欢迎分享本文,谢谢支持!
转载请注明:PHP内核介绍及扩展开发指南——Extensions 的编写:访问PHP变量 | 猎微网

评论已关闭!