上一章用扩展创建了一个变量..
这次来个大的..我们创建一个类.
然后在php里面去调用这个类.
生成扩展及修改 不知道的请点击这里 http://imsiren.com/archives/568
这里就不谈了.
比如我们要创建一个类..PHP代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
classPerson {
public$name;
public$age;
publicfunction__construct() {
echo"construct is running!
";
}
publicfunction__destruct() {
echo"
destruct is running!";
}
publicfunctiongetproperty($key) {
echo$this->$key;
}
publicfunctionsetproperty($key,$val) {
$this->$key=$val;
}
}
|
用PHP来做,很简单..
那么用PHP扩展来写该怎么做?
OK.
1.在php_siren.h里面声明类
1
2
3
4
|
PHP_METHOD(Person,__construct);
PHP_METHOD(Person,__destruct);
PHP_METHOD(Person,setproperty);
PHP_METHOD(Person,getproperty);
|
PHP_METHOD宏.
PHP_METHOD 等于ZEND_METHOD
这个宏接受两个参数,第一个是类名,第二个是类的方法
1
2
3
4
|
#define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_MN(classname##_##name))
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_v alue_used TSRMLS_DC
//最后等于
voidname(intht, zval *return_value, zval **return_value_ptr, zval *this_ptr,intreturn_v alue_used TSRMLS_DC )
|
这个宏是用来声明我们的方法…
2.设置接收的参数
我们的方法如果需要接受参数.那么就要执行
1
2
3
|
ZEND_BEGIN_ARG_INFO_EX(arg_person_info,0,0,2)
ZEND_ARG_INFO(0,name)
ZEND_END_ARG_INFO()
|
详细讲这几个宏之前先看看zend_arg_info
1
2
3
4
5
6
7
8
9
10
11
|
typedefstruct_zend_arg_info {
constchar*name;//参数名称
zend_uint name_len;//长度
constchar*class_name; //所属类名
zend_uint class_name_len; //类名长度
zend_bool array_type_hint;
zend_bool allow_null;//允许为空
zend_bool pass_by_reference; //引用传值
zend_bool return_reference; //引用返回
intrequired_num_args; //参数个数
} zend_arg_info;
|
ZEND_BEGIN_ARG_INFO_EX定义在Zend/zend_API.h
1
2
3
|
#define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \
staticconstzend_arg_info name[] = { \
{ NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
|
很明显 声明一个zend_arg_info的数组name,然后初始化结构体的值
ZEND_ARG_INFO(0,name)的定义如下
1
|
#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 },
|
这三个宏 执行代码 等于
1
2
3
|
staticconstzend_arg_info name[] = { { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
{ #name,sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 },
};
|
3.创建zend_function_entry结构数组
1
2
3
4
5
6
7
|
constzend_function_entry person_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,getproperty,arg_person_info,ZEND_ACC_PUBLIC)
PHP_ME(Person,setproperty,arg_person_info,ZEND_ACC_PUBLIC)
PHP_FE_END
};
|
zend_function_entry定义如下
1
2
3
4
5
6
7
|
typedefstruct_zend_function_entry {
constchar*fname;//函数名称
void(*handler)(INTERNAL_FUNCTION_PARAMETERS);
conststruct_zend_arg_info *arg_info;//参数
zend_uint num_args;//参数个数
zend_uint flags;//标示PUBLIC ?PRIVATE ?PROTECTED
} zend_function_entry;
|
PHP_ME宏接收四个参数
1 类名,
2 方法名,
3 zend_arg_info 的参数列表,
ZEND_ACC_PUBLIC ZEND_ACC_PRIVATE ZEND_ACC_PROTECTED是我们类里面的三个访问权限
ZEND_ACC_CTOR标示构造函数
ZEND_ACC_DTOR标示析构函数
4.修改PHP_MINIT_FUNCTION
前面我们说过 PHP_MINIT_FUNCTION是在模块启动的时候执行的函数
首先创建一个全局指针 zend_class_entry *person_ce;
在PHP_MINIT_FUNCTION加入如下代码
1
2
3
4
|
zend_class_entry person;
INIT_CLASS_ENTRY(person,"Person",person_functions);
person_ce=zend_register_internal_class_ex(&person,NULL,NULL TSRMLS_CC);
zend_declare_property_null(person_ce,ZEND_STRL("name"),ZEND_ACC_PUBLIC TSRMLS_CC);
|
1行创建一个zend_class_entry对象person.
zend_class_entry这个结构体前面也讲过 PHP内核研究之类的实现
2行初始化zend_class_entry 它执行了如下代码
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
30
31
|
{ \
int_len = class_name_len; \
class_container.name = zend_strndup(class_name, _len); \
class_container.name_length = _len; \
class_container.builtin_functiOns= functions; \
class_container.cOnstructor= NULL; \
class_container.destructor = NULL; \
class_container.clOne= NULL; \
class_container.serialize = NULL; \
class_container.unserialize = NULL; \
class_container.create_object = NULL; \
class_container.interface_gets_implemented = NULL; \
class_container.get_static_method = NULL; \
class_container.__call = handle_fcall; \
class_container.__callstatic = NULL; \
class_container.__tostring = NULL; \
class_container.__get = handle_propget; \
class_container.__set = handle_propset; \
class_container.__unset = handle_propunset; \
class_container.__isset = handle_propisset; \
class_container.serialize_func = NULL; \
class_container.unserialize_func = NULL; \
class_container.serialize = NULL; \
class_container.unserialize = NULL; \
class_container.parent = NULL; \
class_container.num_interfaces = 0; \
class_container.interfaces = NULL; \
class_container.get_iterator = NULL; \
class_container.iterator_funcs.funcs = NULL; \
class_container.module = NULL; \
}
|
可以对应文章>> PHP内核研究之类的实现来分析
zend_declare_property_null(person_ce,ZEND_STRL(“name”),ZEND_ACC_PUBLIC TSRMLS_CC);
创建一个值为NULL的属性
第一个参数是类名,第二个参数是 属性名称,第三个参数是属性名的长度,因为ZEND_STRL宏定义了长度,所以这里不用再传递长度.
第四个参数是属性的访问权限.
还有其他几个函数用来创建不同类型的属性
1
2
3
4
5
6
7
|
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
|
5.创建 php_siren.h头文件中的方法体
1
2
3
4
5
6
7
8
9
10
11
12
|
PHP_METHOD(Person,__construct){
php_printf("construct is running
");
}
PHP_METHOD(Person,__destruct){
php_printf("destruct is running
");
}
PHP_METHOD(Person,setproperty){
}
PHP_METHOD(Person,getproperty){
}
|
6.最后make&& make install
编译我们的扩展,
重新启动apache.
$p=new Person();
?>
我们就能在浏览器里看到输出的内容
construct is running
destruct is running
这样 ..我们用扩展创建的一个基本类就完成了.