原文:http://my.oschina.net/mickelfeng/blog/122519?p=1
假设我们要用php扩展实 现一个类person,它有一个private的成员变量$_name和两个public的实例方法getname()和setname(),可以用 php代码表示如下:
?
1
2
3
4
5
6
7
8
9
10
11
12
_name;
}
public function setname($name)
{
$this -> _name = $name;
}
}
1. 声明方法:还使用第一篇文章里面用过的示例,首先在头文件php_fetion_echo.h里加入方法声明。
php_method(person, __construct);php_method(person, __destruct);php_method(person, getname);php_method(person, setname);
前面的扩展在声明函数时使用php_function宏,而在实现类扩展时我们使用php_method宏,第一个参数指定类名,第二个参数指定方法名。
2. 方法实现:在fetion_echo.c文件中实现这几个方法,构造函数和析构函数中只是输出一些文本。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
php_method(person, __construct) {
php_printf(__construct called.);
}
php_method(person, __destruct) {
php_printf(__destruct called.
);
}
php_method(person, getname) {
zval *self, *name;
self = getthis();
name = zend_read_property(z_objce_p(self), self, zend_strl(_name), 0 tsrmls_cc);
return_string(z_strval_p(name), 0);
}
php_method(person, setname) {
char *arg = null;
int arg_len;
zval *value, *self;
if (zend_parse_parameters(zend_num_args() tsrmls_cc, s, &arg, &arg_len) == failure) {
wrong_param_count;
}
self = getthis();
make_std_zval(value);
zval_stringl(value, arg, arg_len, 0);
separate_zval_to_make_is_ref(&value);
zend_update_property(z_objce_p(self), self, zend_strl(_name), value tsrmls_cc);
return_true;
}
对上面的代码做一些解释:
a. 获取方法的参数信息,仍然使用zend_parse_parameters函数,与之前我们介绍过的一样;
b. 获取this指针(相对于php代码而言,在php扩展中仍然使用zval结构表示)使用getthis()函数;
c. 使用make_std_zval宏申请并初始化一个zval结构,在php扩展中,所有的数据类型其实都是用zval结构来表示的,在本系列文章中我会单独写一篇来介绍zval。
d. 获取属性值使用zend_read_property()函数,使用zend_update_property()函数更新属性值。
3. 初始化类:在扩展初始化函数中,注册并初始化类。
zend_class_entry *person_ce;php_minit_function(fetion_echo){ zend_class_entry person; init_class_entry(person, person, fetion_echo_functions); person_ce = zend_register_internal_class_ex(&person, null, null tsrmls_cc); zend_declare_property_null(person_ce, zend_strl(_name), zend_acc_private tsrmls_cc); return success;}
使用init_class_entry宏初始化类,第二个参数指定类名,第三个参数是函数表。
4. 注册到函数:声明方法的参数,并注册到函数表中。
zend_begin_arg_info(arg_person_setname, 0) zend_arg_info(0, name)zend_end_arg_info() const zend_function_entry fetion_echo_functions[] = { php_me(person, __construct, null, zend_acc_public|zend_acc_ctor) php_me(person, __destruct, null, zend_acc_public|zend_acc_dtor) php_me(person, getname, null, zend_acc_public) php_me(person, setname, arg_person_setname, zend_acc_public) {null, null, null} /* must be the last line in fetion_echo_functions[] */ };
类方法参数的声明与之前我们函数参数声明方式一致,在注册类方法到函数表中时使用php_me宏,而不是之前使用的php_fe宏。
zend_acc_public:指定方法的访问修饰符
zend_acc_ctor:指定该方法为构造函数
zend_acc_dtor:指定该方法为析构函数
5. 运行测试:编译安装扩展后,编写一段简单的测试脚本:
setname(mickelfeng); echo $person->getname().'
';
运行后可以看到如下输出,说明扩展工作正常:
__construct called.mickelfeng__destruct called.