这篇开始在扩展中实现PHP的类,先定个目标,实现如下的PHP类:
<?php
class Person {
public const MALE = 1;
public const FEMALE = 2;
private $name;
private $age;
public function __construct(string $name, string $age)
{
$this->name = $name;
$this->age = $age;
}
public function setName(string $name)
{
$this->name = $name;
}
public function getName(): string
{
return $this->name;
}
}
相关结构体、宏及函数
- zend_class_entry: 类入口
- PHP_METHOD: 声明类的方法
- zend_update_property: 更新类的属性
- zend_read_property: 获取类的属性
- PHP_ME: 类方法的参数信息
- INIT_CLASS_ENTRY: 初始化zend_class_entry
- zend_register_internal_class: 向zend中注册类
- zend_declare_property: 声明属性
实现Person类
1. 声明类入口、实现类方法
// 类入口
zend_class_entry *person_ce;
// __construct(string name, int age)
PHP_METHOD(Person, __construct)
{
zend_string *name;
zend_long age;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(name)
Z_PARAM_LONG(age)
ZEND_PARSE_PARAMETERS_END();
// 更新属性
zend_update_property_str(person_ce, getThis(), "name", sizeof("name")-1, name);
zend_update_property_long(person_ce, getThis(), "age", sizeof("age")-1, age);
zend_string_release(name);
}
// getName(): string
PHP_METHOD(Person, getName)
{
zval rv, *name;
name = zend_read_property(person_ce, getThis(), "name", sizeof("name")-1, 0, &rv);
RETURN_STR(Z_STR_P(name))
}
// setName(string name)
PHP_METHOD(Person, setName)
{
zend_string *name;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(name)
ZEND_PARSE_PARAMETERS_END();
zend_update_property_str(person_ce, getThis(), "name", sizeof("name")-1, name);
zend_string_release(name);
}
2. 方法参数信息
ZEND_BEGIN_ARG_INFO(arginfo_person_construct, 0)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, age, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_person_setname, 0)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
ZEND_END_ARG_INFO()
3. 方法入口
与普通函数一样,都是使用zend_function_entry
结构体作为入口,不同的只是把宏换成了PHP_ME
。
zend_function_entry person_methods[] = {
// ZEND_ACC_PUBLIC, 方法访问权限都为public
PHP_ME(Person, __construct, arginfo_person_construct, ZEND_ACC_PUBLIC)
PHP_ME(Person, getName, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Person, setName, arginfo_person_setname, ZEND_ACC_PUBLIC)
PHP_FE_END
};
4. 向Zend注册类
最后在扩展初始化的Hook中,将类注册到Zend中。
PHP_MINIT_FUNCTION(ext_test)
{
// 初始化zend_class_entry,将方法绑定到类中
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Person", person_methods)
// 注册类
person_ce = zend_register_internal_class(&ce);
// 声明类常量
zend_declare_class_constant_long(person_ce, "MALE", sizeof("MALE")-1, 1);
zend_declare_class_constant_long(person_ce, "FEMALE", sizeof("FEMALE")-1, 2);
// 声明类的属性及访问权限
zend_declare_property_null(person_ce, "name", sizeof("name")-1, ZEND_ACC_PRIVATE);
zend_declare_property_null(person_ce, "age", sizeof("age")-1, ZEND_ACC_PRIVATE);
}
至此,类的实现基本完成,大致步骤为:
- 声明类入口
- 实现相关的方法
- 声明方法参数信息
- 声明方法入口
- 在扩展初始化的Hook中注册到Zend中
测试PHP代码
<?php
$person = new Person('anhoder', 18);
var_dump($person->getName());
$person->setName('alan');
var_dump($person);
输出代码:
string(7) "anhoder"
object(Person)#1 (2) {
["name":"Person":private]=>
string(4) "alan"
["age":"Person":private]=>
int(18)
}