目录
- String 的两个宏定义
- 类的初始化 INIT_CLASS_ENTRY
- 类实体的注册 zend_register_internal_class
- 成员函数参数 ZEND_BEGIN_ARG_INFO_EX
- 声明类的成员变量 zend_declare_property
- 声明类常量 zend_declare_class_constant
- 类的初始化示例
- 获取对象句柄 Z_OBJ_HANDLE
- 修改类对象/静态成员变量的值 zend_update_property
- 获取对象自身this 指针 getThis
- 在扩展内创建对象 object_init
- 在扩展中调用对象的方法 zend_call_method_with_0_params
- 获取对象成员变量值 zend_read_property
String 的两个宏定义
在Zend 内核中,针对字符串,定义了两个宏, 这个在后续的字符串处理中经常需要用到,大家留意
----zend_portability.h----
#define ZEND_STRL(str) (str), (sizeof(str)-1)
#define ZEND_STRS(str) (str), (sizeof(str))
类的初始化
//初始化类实体
void INIT_CLASS_ENTRY(zend_class_entry ce, char *classname, zend_function_entry *functions);
| 参数 | 用途 |
| ce | 类实体 zend_class_entry ,存储类的信息,通常用该指针代表一个类 |
| classname | 类名称 |
| functions | 类的成员方法, 定义在 zend_function_entry 结构体数组中。 |
类实体的注册
//注册一般类实体
zend_class_entry *zend_register_internal_class(zend_class_entry *ce TSRMLS_DC);
//注册带父类的实体
zend_class_entry *zend_register_internal_class_ex(zend_class_entry *ce,
zend_class_entry *parent_ce, char *parent_name TSRMLS_DC);
//注册内部类
zend_class_entry *zend_register_internal_interface(zend_class_entry *ce TSRMLS_DC);
| 参数 | 用途 |
| ce | 之前被INIT_CLASS_ENTRY初始化过的类实体 |
| parent_ce | 已经注册过的该类的父类实体 |
| parent_name | 父类的类名 |
一个空类,连构造函数也没有的类实体的注册示例:
----php_swoole.h----
extern zend_class_entry *swoole_server_class_entry_ptr; //类实体的声明
----swoole.c----
//类成员函数的实体
static zend_function_entry swoole_server_methods[] = {
{NULL, NULL, NULL}
};
//类实体
zend_class_entry swoole_server_ce;
zend_class_entry *swoole_server_class_entry_ptr;
...
PHP_MINIT_FUNCTION(swoole)
{
//类的初始化
INIT_CLASS_ENTRY(swoole_server_ce, "swoole_server", swoole_server_methods);
swoole_server_class_entry_ptr = zend_register_internal_class(&swoole_server_ce TSRMLS_CC);
...
}
成员函数参数
//类成员函数的参数宏定义
ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args)
ZEND_ARG_PASS_INFO(by_ref)
ZEND_ARG_INFO(by_ref, name)
ZEND_ARG_ARRAY_INFO(by_ref, name, allow_null)
ZEND_ARG_OBJ_INFO(by_ref, name, classname, allow_null)
ZEND_END_ARG_INFO()
| 参数 | 用途 |
| name | 参数信息名 |
| pass_rest_by_reference | 是否引用传参,如果这个参数设置为1, 所有没有在结构中显式描述的参数都被认为是编译期引用传值的参数. |
| return_reference | 引用返回,告诉Zend你的函数需要用自己的zval覆写return_value_ptr. |
| required_num_args | 必输的参数个数 |
| 宏 | 用途 |
| ZEND_ARG_PASS_INFO | 标识是否对应的参数应该被强制为引用传值 |
| ZEND_ARG_INFO | 普通参数, name 为参数名 |
| ZEND_ARG_ARRAY_INFO | 传入参数必须为数组, name 为参数名, allow_null 是否可以为空 |
| ZEND_ARG_OBJ_INFO | 传入参数必须为对象,name 为参数名, classname 为对象名, allow_null 是否可空 |
声明类的成员变量
int zend_declare_property(zend_class_entry *ce, char *name, int name_length,
zval *value, int access_type TSRMLS_DC);
int zend_declare_property_ex(zend_class_entry *ce, char *name, int name_length,
zval *value, int access_type, char *doc_comment, int doc_comment_len TSRMLS_DC);
int zend_declare_property_null(zend_class_entry *ce, char *name, int name_length,
int access_type TSRMLS_DC);
int zend_declare_property_bool(zend_class_entry *ce, char *name, int name_length,
long value,int access_type TSRMLS_DC);
int zend_declare_property_long(zend_class_entry *ce, char *name, int name_length,
long value, int access_type TSRMLS_DC);
int zend_declare_property_double(zend_class_entry *ce, char *name, int name_length,
double value, int access_type TSRMLS_DC);
int zend_declare_property_string(zend_class_entry *ce, char *name, int name_length,
char *value, int access_type TSRMLS_DC);
int zend_declare_property_stringl(zend_class_entry *ce, char *name, int name_length,
char *value, int value_len, int access_type TSRMLS_DC);
| 参数 | 用途 |
| ce | 类实体 |
| name | 成员变量名 |
| name_length | 不包含结尾符NULL的变量名长度 |
| value | 变量值, 每个函数指定的类型不一样,注意,如果是zval作为成员变量,需要注意zval的内存必须始终分配着 |
| value_len | 该值指定不包含结尾符NULL的value的长度,只在 zend_declare_property_stringl 函数中需要指定 |
| access_type | 成员变量的访问类型,包含ZEND_ACC_PUBLIC, ZEND_ACC_PROTECTED, 或者 ZEND_ACC_PRIVATE,也可以用二进制或 " | " 结合 ZEND_ACC_STATIC 参数使用,将参数定义为类的静态变量 |
声明类常量
int zend_declare_class_constant(zend_class_entry *ce, char *name,
size_t name_length, zval *value TSRMLS_DC);
int zend_declare_class_constant_long(zend_class_entry *ce, char *name,
size_t name_length, long value TSRMLS_DC);
int zend_declare_class_constant_bool(zend_class_entry *ce, char *name,
size_t name_length, zend_bool value TSRMLS_DC);
int zend_declare_class_constant_double(zend_class_entry *ce, char *name,
size_t name_length, double value TSRMLS_DC);
int zend_declare_class_constant_string(zend_class_entry *ce, char *name,
size_t name_length, char *value TSRMLS_DC);
int zend_declare_class_constant_stringl(zend_class_entry *ce, char *name,
size_t name_length, char *value, size_t value_len TSRMLS_DC);
| 参数 | 用途 |
| ce | 类实体 |
| name | 常量名 |
| name_length | 不包含结尾符NULL的常量名长度 |
| value | 常量值, 每个函数指定的类型不一样,注意,如果是zval作为常量,需要注意zval的内存必须始终分配着 |
| value_len | 该值指定不包含结尾符NULL的value的长度,只在 zend_declare_class_constant_stringl 函数中需要指定 |
类的初始化示例
----php7_wrapper.h----
#if PHP_MAJOR_VERSION < 7
#define sw_zend_register_internal_class_ex zend_register_internal_class_ex
#else /* PHP Version 7 */
#define sw_zend_register_internal_class_ex(entry,parent_ptr,str) zend_register_internal_class_ex(entry,parent_ptr)
#endif
----php_swoole.h----
extern zend_class_entry *swoole_server_class_entry_ptr;
//类成员方法的声明
PHP_METHOD(swoole_server, __construct);
PHP_METHOD(swoole_server, __destruct);
PHP_METHOD(swoole_server, set);
#define SW_STRL(s) s, sizeof(s)
----swoole.c----
//参数的定义
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0) //函数无参数
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server__construct, 0, 0, 1) //4个参数,1个必输
ZEND_ARG_INFO(0, host)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, mode)
ZEND_ARG_INFO(0, sock_type)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_set_oo, 0, 0, 1) //一个数组参数
ZEND_ARG_ARRAY_INFO(0, settings, 0)
ZEND_END_ARG_INFO()
//类成员函数的实体
static zend_function_entry swoole_server_methods[] = {
PHP_ME(swoole_server, __construct, arginfo_swoole_server__construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(swoole_server, __destruct, arginfo_swoole_void, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
PHP_ME(swoole_server, set, arginfo_swoole_server_set_oo, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
//类实体
zend_class_entry swoole_server_ce;
zend_class_entry *swoole_server_class_entry_ptr;
...
PHP_MINIT_FUNCTION(swoole)
{
//类的初始化
INIT_CLASS_ENTRY(swoole_server_ce, "swoole_server", swoole_server_methods);
swoole_server_class_entry_ptr = zend_register_internal_class(&swoole_server_ce TSRMLS_CC);
swoole_server_class_entry_ptr->serialize = zend_class_serialize_deny;
swoole_server_class_entry_ptr->unserialize = zend_class_unserialize_deny;
//声明类的成员变量
zend_declare_property_null(swoole_server_class_entry_ptr, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_long(swoole_server_class_entry_ptr, ZEND_STRL("port"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_long(swoole_server_class_entry_ptr, ZEND_STRL("type"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_long(swoole_server_class_entry_ptr, ZEND_STRL("mode"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_bool(swoole_server_class_entry_ptr, ZEND_STRL("connected"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_long(swoole_server_class_entry_ptr, SW_STRL("errCode")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_string(swoole_server_class_entry_ptr, SW_STRL("errMsg")-1, "", ZEND_ACC_PUBLIC TSRMLS_CC);
//声明类常量
zend_declare_class_constant_long(swoole_server_class_entry_ptr, SW_STRL("PIPE_MASTER")-1, 1 TSRMLS_CC);
zend_declare_class_constant_long(swoole_server_class_entry_ptr, SW_STRL("PIPE_WORKER")-1, 2 TSRMLS_CC);
zend_declare_class_constant_long(swoole_server_class_entry_ptr, SW_STRL("PIPE_READ")-1, 3 TSRMLS_CC);
zend_declare_class_constant_long(swoole_server_class_entry_ptr, SW_STRL("PIPE_WRITE")-1, 4 TSRMLS_CC);
}
...
----swoole_server.c----
//函数定义
static PHP_METHOD(swoole_server, __construct)
{
...
return;
}
static PHP_METHOD(swoole_server, __destruct)
{
...
}
static PHP_METHOD(swoole_server, set)
{
...
}
获取对象句柄
zend_object_handle Z_OBJ_HANDLE_P(zval *object) 函数用于获取对象 object 的句柄,相当于对象的一个编号,我们通常用该编号将一些我们自己应用程序的内核信息与对象绑定到一起,例如下面示例,通过 swoole_get_object 方法获取对象句柄,然后获取句柄绑定的服务器配置信息 swServer 指针,注意php5 和 php7 获取句柄的不同。
示例:
----php_swoole.h----
#define SWOOLE_PROPERTY_MAX 32
typedef struct
{
void **array;
uint32_t size;
void **property[SWOOLE_PROPERTY_MAX];
uint32_t property_size[SWOOLE_PROPERTY_MAX];
} swoole_object_array;
swoole_object_array swoole_objects;
static sw_inline void* swoole_get_object(zval *object)
{
#if PHP_MAJOR_VERSION < 7
zend_object_handle handle = Z_OBJ_HANDLE_P(object);
#else
int handle = (int)Z_OBJ_HANDLE(*object);
#endif
return swoole_objects.array[handle];
}
----swoole_server.c----
PHP_METHOD(swoole_server, set)
{
zval *zset = NULL;
zval *zobject = getThis();
HashTable *vht;
zval *v;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zset) == FAILURE)
{
return;
}
//获取对象挂载的服务器配置信息 swServer
swServer *serv = swoole_get_object(zobject);
vht = Z_ARRVAL_P(zset);
if (php_swoole_array_get_value(vht, "reactor_num", v))
{
convert_to_long(v);
serv->reactor_num = (int) Z_LVAL_P(v);
if (serv->reactor_num <= 0)
{
serv->reactor_num = SwooleG.cpu_num;
}
}
...
}
修改类对象/静态成员变量的值
//成员变量修改
void zend_update_property(zend_class_entry *scope, zval *object, char *name, int name_length, zval *value TSRMLS_DC);
void zend_update_property_null(zend_class_entry *scope, zval *object, char *name, int name_length TSRMLS_DC);
void zend_update_property_bool(zend_class_entry *scope, zval *object, char *name, int name_length, long value TSRMLS_DC);
void zend_update_property_long(zend_class_entry *scope, zval *object, char *name, int name_length, long value TSRMLS_DC);
void zend_update_property_double(zend_class_entry *scope, zval *object, char *name, int name_length, double value TSRMLS_DC);
void zend_update_property_string(zend_class_entry *scope, zval *object, char *name, int name_length, char *value TSRMLS_DC);
void zend_update_property_stringl(zend_class_entry *scope, zval *object, char *name, int name_length, char *value, int value_len TSRMLS_DC);
//静态成员变量修改
int zend_update_static_property(zend_class_entry *scope, char *name, int name_length, zval *value TSRMLS_DC);
int zend_update_static_property_null(zend_class_entry *scope,char *name, int name_length TSRMLS_DC);
int zend_update_static_property_bool(zend_class_entry *scope, char *name, int name_length, long value TSRMLS_DC);
int zend_update_static_property_long(zend_class_entry *scope, char *name, int name_length, long value TSRMLS_DC);
int zend_update_static_property_double(zend_class_entry *scope, char *name, int name_length, double value TSRMLS_DC);
int zend_update_static_property_string(zend_class_entry *scope, char *name, int name_length, char *value TSRMLS_DC);
int zend_update_static_property_stringl(zend_class_entry *scope, char *name, int name_length, char *value, int value_len TSRMLS_DC);
| 参数 | 属性 |
| scope | 类实体,指明修改哪个类的成员变量 |
| object | 类对象, 静态成员变量是属于整个类共有变量,不属于单个对象, 所以没有 object 参数 |
| name | 变量名 |
| name_length | 不包含最后的 NULL 结束符的变量长度 |
| value | 变量值, 每个函数指定的类型不一样,注意,如果是zval作为成员变量,需要注意zval的内存必须始终分配着 |
| value_len | 该值指定不包含结尾符NULL的value的长度,只在 zend_update_property_stringl / zend_update_static_property_stringl 函数中需要指定 |
示例:
static zval* create_object(char * host, int port)
{
zval * server_object;
SW_ALLOC_INIT_ZVAL(server_object); //php5 php7 适配的内存分配
object_init_ex(server_object, swoole_server_class_entry_ptr);
...
zend_update_property_string(swoole_server_class_entry_ptr, server_object, ZEND_STRL("host"), host TSRMLS_CC);
zend_update_property_long(swoole_server_class_entry_ptr, server_object, ZEND_STRL("port"), port TSRMLS_CC);
zend_update_static_property_long(swoole_server_class_entry_ptr, ZEND_STRL("uniqueId"), 0 TSRMLS_CC);
zend_update_static_property_bool(swoole_server_class_entry_ptr, ZEND_STRL("checked"), 1 TSRMLS_CC);
return server_object;
}
获取对象自身 this 指针
zval * getThis();
示例:
static PHP_METHOD(swoole_buffer, __construct)
{
long size = SW_STRING_BUFFER_DEFAULT; //默认大小
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &size) == FAILURE)
{
RETURN_FALSE;
}
...
zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("capacity"), size TSRMLS_CC);
zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("length"), 0 TSRMLS_CC);
}
在扩展内创建对象
int object_init(zval *arg);
int object_init_ex(zval *arg, zend_class_entry *ce);
int object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties TSRMLS_DC);
| 参数 | 用途 |
| arg | 需要被初始化的对象的 zval 指针 |
| ce | 将要被初始化的类的类实体,指明哪个类会被初始化 |
| properties | 用初始属性代替类的默认属性, |
在扩展内创建对象,因为在php中,对象也是一个zval, 所以我们需要首先创建zval, 然后为 zval 分配内存
最后调用 object_init_ex 函数初始化为对象类型,至于是哪个,由 zend_class_entry 指定,如下, swoole_server_port 对象被初始化了,然后用 zend_update_property_string 和 zend_update_property_long 更新 swoole_server_port对象的,host以及port属性。
示例:
static zval* create_object(char * host, int port)
{
zval *port_object;
SW_ALLOC_INIT_ZVAL(port_object); //php5 php7 适配的内存分配
object_init_ex(port_object, swoole_server_port_class_entry_ptr);
...
zend_update_property_string(swoole_server_port_class_entry_ptr, port_object, ZEND_STRL("host"), host TSRMLS_CC);
zend_update_property_long(swoole_server_port_class_entry_ptr, port_object, ZEND_STRL("port"), port TSRMLS_CC);
return port_object;
}
在扩展中调用对象的方法
void zend_call_method_with_0_params(zval** obj, zend_class_entry *ce, zend_function **fn_proxy, char* function_name, zval ** retval)
void zend_call_method_with_1_params (zval** obj, zend_class_entry *ce, zend_function **fn_proxy, char* function_name, zval ** retval, zval * v1)
void zend_call_method_with_2_params (zval** obj, zend_class_entry *ce, zend_function **fn_proxy, char* function_name, zval ** retval, zval * v1, zval *v2)
| 参数 | 用途 |
| obj | 被调用的对象的 zval 指针 |
| ce | 被调用的类的类实体,指明哪个类被调用了 |
| fn_proxy | 代理函数 |
| function_name | 成员方法名,指定该类的哪个成员方法将会被调用 |
| retval | 返回值,也是一个 zval指针 |
| v1/v2 | 传入参数 |
在下面示例,服务器端口类 swoole_server_port 的set 方法被调用了。
----php7_wrapper.h----
#if PHP_MAJOR_VERSION < 7 /* PHP Version 5*/
#define sw_zend_call_method_with_0_params zend_call_method_with_0_params
#define sw_zend_call_method_with_1_params zend_call_method_with_1_params
#define sw_zend_call_method_with_2_params zend_call_method_with_2_params
#else /* PHP Version 7 */
#define sw_zend_call_method_with_0_params(obj, ptr, what, method, retval) \
zval __retval;\
zend_call_method_with_0_params(*obj, ptr, what, method, &__retval);\
if (ZVAL_IS_NULL(&__retval)) *(retval) = NULL;\
else *(retval) = &__retval;
#define sw_zend_call_method_with_1_params(obj, ptr, what, method, retval, v1) \
zval __retval;\
zend_call_method_with_1_params(*obj, ptr, what, method, &__retval, v1);\
if (ZVAL_IS_NULL(&__retval)) *(retval) = NULL;\
else *(retval) = &__retval;
#define sw_zend_call_method_with_2_params(obj, ptr, what, method, retval, v1, v2) \
zval __retval;\
zend_call_method_with_2_params(*obj, ptr, what, method, &__retval, v1, v2);\
if (ZVAL_IS_NULL(&__retval)) *(retval) = NULL;\
else *(retval) = &__retval;
#endif /* PHP Version */
----test.c----
PHP_METHOD(call_swoole_server_port_function_set)
{
zval *port_object = getServerPortObject(); //获取 swoole_server_port 类的对象
zval *zset; //传入参数
zval *retval = NULL; //返回值
....
sw_zend_call_method_with_1_params(&port_object, swoole_server_port_class_entry_ptr, NULL, "set", &retval, zset);
...
}
获取对象成员变量值
//更新对象属性
zval *zend_read_property(zend_class_entry *scope, zval *object, char *name,
int name_length, zend_bool silent TSRMLS_DC);
//更新类的静态属性
zval *zend_read_static_property(zend_class_entry *scope, char *name,
int name_length, zend_bool silent TSRMLS_DC);
| 参数 | 属性 |
| scope | 类实体,指明修改哪个类的成员变量 |
| object | 类对象, 静态成员变量是属于整个类共有变量,不属于单个对象, 所以没有 object 参数 |
| name | 成员变量名 |
| name_length | 变量名的长度,不包含最后的 NULL 字符 |
| silent | 设置为非零值时,不会报告“undefined property”错误。 注意:未定义 read_property 处理程序的实例将报告错误,而不管silent参数如何。 |
示例读取 swoole_server_port 对象的参数设置 setting 的值:
#if PHP_MAJOR_VERSION < 7 /* PHP Version 5*/
#define sw_zend_read_property zend_read_property
#else /* PHP Version 7 */
static inline zval* sw_zend_read_property(zend_class_entry *class_ptr, zval *obj, char *s, int len, int silent)
{
zval rv;
return zend_read_property(class_ptr, obj, s, len, silent, &rv);
}
#endif /* PHP Version */
//获取对象属性值,如果为空,则初始化为空数组
static inline zval* php_swoole_read_init_property(zend_class_entry *scope, zval *object, const char *p, size_t pl TSRMLS_DC)
{
zval *property = sw_zend_read_property(scope, object, p, pl, 1 TSRMLS_CC);
if (property == NULL || ZVAL_IS_NULL(property))
{
SW_MAKE_STD_ZVAL(property);
array_init(property);
zend_update_property(scope, object, p, pl, property TSRMLS_CC);
sw_zval_ptr_dtor(&property);
return sw_zend_read_property(scope, object, p, pl, 1 TSRMLS_CC);
}
else
{
return property;
}
}
PHP_METHOD(swoole_server_port, set)
{
...
zval *zsetting = php_swoole_read_init_property(swoole_server_port_class_entry_ptr, getThis(), ZEND_STRL("setting") TSRMLS_CC);
...
}
本文详细介绍了PHP扩展开发中对象的相关操作,包括类的初始化、实体注册、成员函数参数声明、成员变量和常量的声明、对象句柄获取、修改对象属性、调用对象方法及获取对象成员变量值等关键步骤,附带了多个示例代码。
1501

被折叠的 条评论
为什么被折叠?



