Обработчики объектов¶
Почти все операции над объектами в 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)
Эти обработчики соответствуют методам
__get,__set,__issetи__unset.get_property_ptr_ptr— это внутренний эквивалент__get, возвращающий значение по ссылке.cache_slotиспользуется для хранения смещения свойства иzend_property_info.read_propertyможет напрямую вернуть zval, принадлежащий объекту, в этом случае его счётчик ссылок не должен изменятьсяread_property, и вызывающая сторона не должна его освобождать. В качестве альтернативы, он может вернутьrvдля временных zval (например, результат вызова__get), в этом случае счётчик ссылок должен быть увеличен, и ответственность за освобождение значения лежит на вызывающей стороне.
-
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.zval *rvвread_dimensionиспользуется для временных значений, возвращаемых изoffsetGetиoffsetExists.
-
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— это обязательный обработчик, который вычисляет равенство данного объекта и другого значения. Обратите внимание, что другое значение не обязательно является объектом того же класса, или даже объектом вообще. Обработчик должен возвращать отрицательные числа, если левый операнд меньше, 0, если они равны, или положительное число, если левый операнд больше. Если значения несравнимы, должно быть возвращено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_objвызывается при выполненииclone $old_object. По умолчанию 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_objвызывается передfree_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_r,var_dump, приведение к(array),serialize,var_exportиjson_encode.