自己写PHP扩展之操作类的属性和方法[原创]
作者 斯人 | 发布于 2012 年 4 月 26 日
PHP PHP内核

类创建好了..
那么类肯定不止这些东西,它由继承,属性,返回值等.

1.方法的参数.
有方法,该方法就可能要有参数.参数是如何传递过来的呢?
如果看过之前的文章.那么你肯定就知道了..是的 与普通函数的参数相同.
声明char类型的指针用来保存参数的值.
声明int类型的变量来保存的参数长度
然后用到 zend_parse_parameters函数
zend_parse_parameters(``,`< char *type_spec>`,`< ...>`)
该参数有几个重要的参数
第一个是参数的个数
第二个比较重要,它指定接收参数的类型
下面这份清单完整地列举出了我们可以指定接收的参数类型:

l – 长整数

d – 双精度浮点数

s – 字符串 (也可能是空字节)和其长度

b – 布尔值

r – 资源, 保存在 zval*

a – 数组, 保存在 zval*

o – (任何类的)对象, 保存在 zval*

O – (由class entry 指定的类的)对象, 保存在 zval*

z – 实际的 zval*

下面的一些字符在类型说明字符串(就是那个 char *type_spec)中具有特别的含义:

| – 表明剩下的参数都是可选参数。如果用户没有传进来这些参数值,那么这些值就会被初始化成默认值。

/ – 表明参数解析函数将会对剩下的参数以 SEPARATE_ZVAL_IF_NOT_REF() 的方式来提供这个参数的一份拷贝,除非这些参数是一个引用。

! – 表明剩下的参数允许被设定为 NULL(仅用在 a、o、O、r和z身上)。如果用户传进来了一个 NULL 值,则存储该参数的变量将会设置为 NULL。
函数 get接收两个参数 ,第一个参数是必填字符串类型,第二个参数是可选为整型.
PHP代码如下

function get($name,$age=0){

}

如果要在扩展里实现这样的功能,zend_parse_parameters的使用如下
char* name;
int name_length;
int age;
int age_length;
zend_parse_parameters(ZEND_NUM_ARGS ,”s|l”,&name,&name_length,&age,&age_len)
zend_parse_parameters 执行失败的话会返回FAILURE.
执行成功后,name就是第一个参数的值,age就是第二个参数的值
我们甚至可以调用php_printf函数来输出.

2.类的属性
这类的内容在上一篇文章中其实已经讲清楚了.
用zend_declare_property_*一系列函数来创建我们的属性.当然是在PHP_MINIT_FUNCTION函数中创建
以 zend_declare_property_null为例:
zend_declare_property_null(``,`< char *name>`,`< int name_length>`,`< int access_type TSRMLS_DC>`)
ce :是一个zend_class_entry的指针.
name :是属性的名称
length :属性名称的长度
access_type:属性的访问级别.
还有其他几个函数 用法一样.

        zend_declare_property_bool
        zend_declare_property_double
        zend_declare_property_ex
        zend_declare_property_long
        zend_declare_property_null
        zend_declare_property_string
        zend_declare_property_stringl

3.读取属性
创建了属性,那么该如何读取此属性呢?
zend_read_property(``,`< zval *object>`,`< char *name>`,`< int name_length>`,`< zend_bool silent TSRMLS_DC>`);
就要使用这个函数了,它将获取到的属性信息返回到一个zval结构体中
这时候要用到函数getThis();
这个函数会返回一个zval的指针.
因为是一个对象 所以保存在结构体_zend_object_value 中
typedef struct _zend_object_value {
zend_object_handle handle;
zend_object_handlers *handlers;
} zend_object_value;
第一个参数会调用 zend_object_handler所指向的函数指针get_class_entry来获取当前执行的类的信息.
第一个参数应该是 Z_OBJEC_P(getThis());
第二个参数是 getThis();
它定义为 #define getThis() (this_ptr);
this_ptr是什么东西我还不确定,我想应该是PHP内核维护的一个保存类信息的zval对象.回头再好好研究研究.
第三个参数是要获取的属性
第四个参数是属性的长度.
修改之后的getproperty方法

PHP_METHOD(Person,getproperty){
        zval* self=getThis();
        zval* name;
        name=zend_read_property(Z_OBJCE_P(self),self,ZEND_STRL("name"),0 TSRMLS_CC);
        php_printf("%s",name->value.str.val);
}

4.设置属性
该如何更新属性的值呢?
同样给我们提供了一个函数
zend_update_property(``,`< zval *object>`,`< char *name>`,`< int name_length>`,`< zval *value TSRMLS_DC>`)
前四个参数与zend_read_property相同.
不同的是最后一个zval*value.它是我们属性的值..因为他是一个zval的指针,所以我们需要将通过zend_parse_parameters获取到的参数转为一个zval的指针.
修改后的setproperty方法.

PHP_METHOD(Person,setproperty){
        char *key=NULL;
        int key_len;
        char *val=NULL;
        int val_len;
        zval* self=getThis();
        zval* value;
        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"ss",&key,&key_len,&val,&val_len)==FAILURE){
                return;
        }   
        MAKE_STD_ZVAL(value);
        ZVAL_STRINGL(value,val,val_len,1);
        zend_update_property(Z_OBJCE_P(self),self,key,key_len,value TSRMLS_CC);

最后make && make install,重启apache.
这样我们在 php代码里.

<?php
$a=new Person();
$a->setproperty("name","this is siren");
$a->getproperty();
?>

就可以输出我们通过setproperty设置的值了.

原文出处:http://www.imsiren.com/archives/581