对象处理器

PHP 中几乎所有的对象操作都通过对象处理程序进行,并且每个魔法方法或魔法接口都使用对象或类处理程序在内部实现。此外,还有相当多的处理程序未向用户空间 PHP 公开。例如,内部类可以具有自定义比较和强制类型转换行为。

概览

这里是所有对象处理程序及其签名和简短描述。

zval *read_property(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv)
zval *write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot)
int has_property(zend_object *zobj, zend_string *name, int has_set_exists, void **cache_slot)
void unset_property(zend_object *zobj, zend_string *name, void **cache_slot)
zval *get_property_ptr_ptr(zend_object *zobj, zend_string *name, int type, void **cache_slot)

这些处理程序对应于 getsetissetunset 方法。get_property_ptr_ptrget 的内部等价物,通过引用返回。cache_slot 用于存储属性偏移量和 zend_property_inforead_property 可以直接返回对象拥有的 zval,在这种情况下,其引用计数不应由 read_property 修改,调用者也不应该释放它。或者,它可以为临时 zval(例如调用 get 的结果)返回 rv,在这种情况下,引用计数应该增加,调用者负责释放该值。

zval *read_dimension(zend_object *object, zval *offset, int type, zval *rv)
void write_dimension(zend_object *object, zval *offset, zval *value)
int has_dimension(zend_object *object, zval *offset, int check_empty)
void unset_dimension(zend_object *object, zval *offset)

这组处理程序是 ArrayAccess 接口的内部表示。read_dimension 中的 zval *rv 用于从 offsetGetoffsetExists 返回的临时值。

HashTable *get_properties(zend_object *zobj)
HashTable *get_debug_info(zend_object *object, int *is_temp)

用于以哈希表形式获取对象属性。前者用途更广泛,例如,它还用于 get_object_vars 函数。而后者则专门用于在调试函数(如 var_dump)中显示属性。因此,即使您的对象不提供任何正式属性,您仍然可以获得有意义的调试输出。

zend_function *get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key)

get_method 处理程序获取用于调用特定方法的 zend_function。可选地,可以传递 key 作为优化,以避免在 method_name 已经存在的情况下将其小写。

zend_function *get_constructor(zend_object *zobj)

类似于 get_method,但获取的是构造函数。覆盖此处理程序的最常见原因是通过在处理程序中抛出错误来禁止手动构造。

zend_result count_elements(zend_object *object, zend_long *count)

这只是 Countable::count 方法的内部实现,函数返回一个 zend_result,并将值赋给 zend_long *count 指针。

int compare(zval *o1, zval *o2)

compare 处理程序是必需的处理程序,用于计算给定对象和另一个值的相等性。请注意,另一个值不一定是同一类的对象,甚至根本不是对象。如果 lhs 较小,处理程序应返回负数;如果它们相等,则返回 0;如果 lhs 较大,则返回正数。如果值无法比较,则应返回 ZEND_UNCOMPARABLE

zend_result cast_object(zend_object *readobj, zval *writeobj, int type)

内部类能够实现自定义比较行为并覆盖所有类型的转换行为。另一方面,用户空间类只能通过 __toString 覆盖对象到字符串的转换。

zend_result get_closure(zend_object *obj, zend_class_entry ce_ptr, zend_function fptr_ptr, zend_object **obj_ptr, bool check_only)

当对象用作函数时,将调用此处理程序,即它是 __invoke 的内部版本。该名称源于其主要用途是实现闭包(Closure 类)。

zend_string *get_class_name(const zend_object *zobj)

此处理程序用于从对象中获取类名,用于调试上下文。应该没有必要覆盖它。

zend_object *clone_obj(zend_object *old_object)

执行 clone $old_object 时会调用 clone_obj 处理程序。默认情况下,PHP 对对象执行浅克隆,这意味着包含对象的属性不会被克隆,但旧对象和新对象都将指向同一对象。 clone_obj 允许自定义此行为。它还用于完全禁止 clone

HashTable *get_gc(zend_object *zobj, zval **table, int *n)

get_gc 处理程序应返回对象所持有的所有变量,以便正确收集循环依赖项。如果对象不维护属性哈希图(因为它不存储任何动态属性),它可以使用 table 将指针直接存储到 zval 列表中,以及属性计数。

void dtor_obj(zend_object *object)
void free_obj(zend_object *object)

dtor_objfree_obj 之前被调用。dtor_obj 运行结束后,对象必须保持有效状态。与 free_obj 不同,它在关闭期间执行器停用之前运行,这允许用户代码运行。此处理程序不保证被调用(例如,在发生致命错误时),因此不应将其用于释放资源或释放内存。此外,在此处理程序中释放资源可能会中断内存泄漏检测,因为循环可能会提前中断。dtor_obj 应仅用于调用用户销毁钩子,例如 __destruct

free_obj 应释放对象持有的任何资源,而不释放对象结构本身。free_obj 运行结束后,对象不需要处于有效状态。free_obj 将始终被调用,即使对象泄漏或发生致命错误。但是,在关闭期间,一旦执行器不再处于活动状态,它可能会调用,在这种情况下,可能会跳过用户代码的执行。

zend_result do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2)

do_operation 是一个可选的处理程序,它将被调用来对给定类的实例执行各种算术和二进制运算。这允许为自定义类实现运算符重载语义。可重载运算符的示例有 +-*/++--!

zend_array *get_properties_for(zend_object *object, zend_prop_purpose purpose)

get_properties_for 可用于自定义返回的对象属性列表,用于各种目的。这些目的在 zend_prop_purpose 中定义,目前包括 print_rvar_dump(array) cast、serializevar_exportjson_encode