PHP7/5扩展开发函数手册(5) - 对象

类的初始化

//初始化类实体
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  父类的类名

类参数

//类的参数宏定义
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()

ZEND_BEGIN_ARG_INFO_EX 宏用于声明参数的属性:

参数                                                         用途

  • 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 是否可空

示例:

----php_swoole.h---- 文件

extern zend_class_entry *swoole_server_port_class_entry_ptr;

----swoole_server_port.c----文件

//PHP类的定义
zend_class_entry swoole_server_port_ce;
zend_class_entry *swoole_server_port_class_entry_ptr;  //类指针

static PHP_METHOD(swoole_server_port, __construct); //构造函数
static PHP_METHOD(swoole_server_port, __destruct); //析构函数
static PHP_METHOD(swoole_server_port, set); //set函数

ZEND_BEGIN_ARG_INFO_EX(arginfo_server_void, 0, 0, 0) //函数无参数
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server_port_set, 0, 0, 1) //set函数的参数带一个
    ZEND_ARG_ARRAY_INFO(0, settings, 0)
ZEND_END_ARG_INFO()

//类的方法
const zend_function_entry swoole_server_port_methods[] =
{
    PHP_ME(swoole_server_port, __construct,     arginfo_server_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
    PHP_ME(swoole_server_port, __destruct,      arginfo_server_void, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
    PHP_ME(swoole_server_port, set,      arginfo_swoole_server_port_set, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
    PHP_FE_END
};

PHP_MINIT_FUNCTION(test)
{
    //类的初始化
    INIT_CLASS_ENTRY(swoole_server_port_ce, "swoole_server_port", swoole_server_port_methods);
    swoole_server_port_class_entry_ptr = zend_register_internal_class(&swoole_server_port_ce TSRMLS_CC);
    swoole_server_port_class_entry_ptr->serialize = zend_class_serialize_deny;
    swoole_server_port_class_entry_ptr->unserialize = zend_class_unserialize_deny;
    
    //声明类的属性 host 为 null 类型
    zend_declare_property_null(swoole_server_port_class_entry_ptr, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC);
    //声明类的属性 port 为整数
    zend_declare_property_long(swoole_server_port_class_entry_ptr, ZEND_STRL("port"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
}

//函数定义
static PHP_METHOD(swoole_server_port, __construct)
{
    ...
    return;
}

static PHP_METHOD(swoole_server_port, __destruct)
{
	...
}

static PHP_METHOD(swoole_server_port, set)
{
	...
}

 

在扩展内创建类对象

对象初始化函数:object_init_ex(zval *val, zend_class_entry *ce)

在扩展内创建对象,因为在php中,对象也是一个zval, 所以我们需要首先创建zval, 然后为 zval 分配内存 

最后调用 object_init_ex(zval *val, zend_class_entry *ce) 函数初始化为对象类型,至于是哪个,由 zend_class_entry 指定

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;
}

在扩展中调用对象的方法

zend_call_method_with_0_params(zval** obj, zend_class_entry *ce, void * what, char* method, zval ** retval)

zend_call_method_with_1_params (zval** obj, zend_class_entry *ce, void * what, char* method, zval ** retval, zval * v1)

zend_call_method_with_2_params (zval** obj, zend_class_entry *ce, void * what, char* method, zval ** retval, zval * v1, zval *v2)

----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);

#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);
	...
}

猜你喜欢

转载自blog.csdn.net/caohao0591/article/details/82191283