zend_object 对象的新建和操作

要说操作zend_object 先要熟悉下怎么在扩展中定义类 zend_class_entry, 可以读读这篇文章了解下如何在扩展中定义类

类定义

简要说下定义类的关键点

zend_class_entry *myclass_ce;

static zend_function_entry myclass_method[] = {
    { NULL, NULL, NULL }
};

PHP_MINIT_FUNCTION(academy_sample_class)
{
    zend_class_entry ce;

    //myclass是这个类的名称
    INIT_CLASS_ENTRY(ce, "myclass", myclass_method);  
//这里定义了类名和方法,初始化zend_class_entry这个结构体
    myclass_ce = zend_register_internal_class(&ce TSRMLS_CC);
 //这里是把这个zend_class_entry 这个初始化的结构体放到CG(class_table)这个编译时全局变量hash table 中 
    return SUCCESS;
}

我们上面还定义了一个 myclass_ce 指针,它是干什么用的呢?当我们在扩展中对这个类进行操作,比如生成实例的时候,会使用到它,它的作用就类似于打开文件的操作句柄。


/*************zend_API.C*****************/
ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *orig_class_entry) /* {{{ */
{
    return do_register_internal_class(orig_class_entry, 0);
}

/*************zend_API.C*****************/
static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class_entry, uint32_t ce_flags) /* {{{ */
{
    zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
    zend_string *lowercase_name = zend_string_alloc(ZSTR_LEN(orig_class_entry->name), 1);
    *class_entry = *orig_class_entry;

    class_entry->type = ZEND_INTERNAL_CLASS;
    zend_initialize_class_data(class_entry, 0);
    class_entry->ce_flags = ce_flags | ZEND_ACC_CONSTANTS_UPDATED;
    class_entry->info.internal.module = EG(current_module);

    if (class_entry->info.internal.builtin_functions) {
        zend_register_functions(class_entry, class_entry->info.internal.builtin_functions, &class_entry->function_table, MODULE_PERSISTENT);
    }

    zend_str_tolower_copy(ZSTR_VAL(lowercase_name), ZSTR_VAL(orig_class_entry->name), ZSTR_LEN(class_entry->name));
    lowercase_name = zend_new_interned_string(lowercase_name);
    zend_hash_update_ptr(CG(class_table), lowercase_name, class_entry);//把 zend_class_entry 注册到CG(class_table) hash table 中
    zend_string_release(lowercase_name);
    return class_entry;
}

对象创建销毁

/**********zend_objects.h************/

ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce);  //创建和初始化对象
ZEND_API void zend_object_std_dtor(zend_object *object);
ZEND_API zend_object *zend_objects_new(zend_class_entry *ce); //新建对象
ZEND_API void zend_objects_destroy_object(zend_object *object);
ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object *old_object);
ZEND_API zend_object *zend_objects_clone_obj(zval *object);

对象属性操作

/**********zend_API.c************/

//更新属性
ZEND_API void zend_update_property_ex(zend_class_entry *scope, zval *object, zend_string *name, zval *value);
ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zval *value);
ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, const char *name, size_t name_length);
ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value);
ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value);
ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, const char *name, size_t name_length, double value);
ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_string *value);
ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value);
ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value, size_t value_length);

//更新静态属性
ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *name, size_t name_length, zval *value);
ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const char *name, size_t name_length);
ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const char *name, size_t name_length, zend_long value);
ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const char *name, size_t name_length, zend_long value);
ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const char *name, size_t name_length, double value);
ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const char *name, size_t name_length, const char *value);
ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const char *name, size_t name_length, const char *value, size_t value_length);

读对象属性和静态属性
ZEND_API zval *zend_read_property_ex(zend_class_entry *scope, zval *object, zend_string *name, zend_bool silent, zval *rv);
ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_bool silent, zval *rv);
ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, size_t name_length, zend_bool silent);

//声明对象常量和update常量值
ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment);
ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value);
ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length);
ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value);
ZEND_API int zend_declare_class_constant_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_bool value);
ZEND_API int zend_declare_class_constant_double(zend_class_entry *ce, const char *name, size_t name_length, double value);
ZEND_API int zend_declare_class_constant_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_length);
ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value);

ZEND_API int zend_update_class_constants(zend_class_entry *class_type);

对象方法调用

//Zend/zend_interfaces.h

ZEND_API zval* zend_call_method(zval *object_pp, zend_class_entry *obj_ce, zend_function **fn_proxy, const char *function_name, size_t function_name_len, zval *retval, int param_count, zval* arg1, zval* arg2);

zend_call_method_with_0_params(obj, obj_ce, fn_proxy, function_name, retval) 
zend_call_method_with_1_params(obj, obj_ce, fn_proxy, function_name, retval, arg1) 
zend_call_method_with_2_params(obj, obj_ce, fn_proxy, function_name, retval, arg1, arg2) 

这里有个问题,调用函数方法貌似最多传2个参数,那么多余两个参数的方法调用要怎么办呢?
这个需要自己去封装 zend_call_function() , 可以参考这篇文章https://www.cnblogs.com/djhull/p/5359634.html

类的方法中操作对象demo

PHP_METHOD(Person, __construct) {
 php_printf("__construct called.");
}

PHP_METHOD(Person, __destruct) {
 php_printf("__destruct called.<br/>");
}

PHP_METHOD(Person, getName) {
 zval *self, *name;
 self = getThis();  //获取当前对象, 相当于 this指针
 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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352