php object 对象系统

php object 对象系统

概述

本节内容仅谈论对象系统内容, 对于相关内容并不作更深一步的扩展, 相关扩展的内容会在后续补充php

object 对象属于 zval 结构的一种形式算法

php 将全部执行过程当中的 object 放在一个对象池中进行管理 EG(objects_store)api

结构

  • zval 结构 (Zend/zend.h)app

    • struct _zval_struct { // PHP存储变量的结构
          zvalue_value value; // 值
          zend_uint refcount__gc; // 引用计数
          zend_uchar type; // 类型标识, IS_NULL, IS_BOOL, IS_STRING ...
          zend_uchar is_ref__gc; //是否为引用
      };
  • value 结构 (Zend/zend.h)函数

    • typedef union _zvalue_value { // 变量存储的值结构
          // 省略 ...
          zend_object_value obj; // 存储对象,参见zend_types.h
      } zvalue_value;
  • zend_object_value 结构 (Zend/zend_types.h)ui

    • typedef struct _zend_object_value {
         /*
         * php 内核会将全部对象存放在一个对象容器中: EG(objects_store).object_buckets
         * handle 参数是对象在这个容器中的索引, 无符号整数
         */
          zend_object_handle handle;
         // 对象属性, 方法的操做函数: Zend/zend_object_handlers.h
          const zend_object_handlers *handlers;
      } zend_object_value;
      • 执行过程当中的全局结构体 zend_executor_globals (Zend/zend_globals.h)debug

        • // 运行时的全局数据
          struct _zend_executor_globals {
              // 省略 ...
          
              // 当前符号表
              HashTable *active_symbol_table;
              // 符号表
              HashTable symbol_table;
              // 函数表
              HashTable *function_table;
              // 类表
              HashTable *class_table;
              // 常量表
              HashTable *zend_constants;
              zend_class_entry *scope;
              zend_class_entry *called_scope; /* Scope of the calling class */
              // 对象池
              zend_objects_store objects_store;
          
              // 省略 ...
          };
      • 对象池 zend_objects_store (Zend/zend_objects_API.h)code

        • // 对象池, 存放 php 中间代码运行过程当中生成的全部对象
          typedef struct _zend_objects_store {
              // 对象容器
              zend_object_store_bucket *object_buckets;
              zend_uint top;
              zend_uint size;
              int free_list_head;
          } zend_objects_store;
        • 对象池的初始化在 request RINIT对象

          // 初始化执行器
          void init_executor(TSRMLS_D)
          {
              // 省略 ...
          
              zend_objects_store_init(&EG(objects_store), 1024);
          
              // 省略 ...
          }
          // 对象池的初始化
          ZEND_API void zend_objects_store_init(zend_objects_store *objects, zend_uint init_size)
          {
              objects->object_buckets = (zend_object_store_bucket *) emalloc(init_size * sizeof(zend_object_store_bucket));
              objects->top = 1; /* Skip 0 so that handles are true */
              objects->size = init_size;
              objects->free_list_head = -1;
              memset(&objects->object_buckets[0], 0, sizeof(zend_object_store_bucket));
          }
        • 对象池的释放在 request RSHUTDOWN索引

          // 释放各变量的析构方法
          void shutdown_destructors(TSRMLS_D)
          {
                  // 省略 ...
          
                  zend_objects_store_call_destructors(&EG(objects_store) TSRMLS_CC);
          
                  // 省略 ...
          }
          // 关闭对象池
          void shutdown_executor(TSRMLS_D)
          {
                  // 省略 ...
          
                  zend_objects_store_destroy(&EG(objects_store));
          
                  // 省略 ...
          }
        • 对象容器 zend_object_store_bucket (Zend/zend_objects_API.h)

          /*
          * 对象哈希表桶结构
          * 解决冲突的哈希算法为连接法
          * 哈希冲突解决办法有两种:
          *   1. 连接法
          *   2. 开放寻址法
          */
          typedef struct _zend_object_store_bucket {
              zend_bool destructor_called;
              zend_bool valid;
              zend_uchar apply_count;
              union _store_bucket {
                  struct _store_object {
                      // 对象数据, zend_object 结构
                      void *object;
                      zend_objects_store_dtor_t dtor;
                      zend_objects_free_object_storage_t free_storage;
                      zend_objects_store_clone_t clone;
                      const zend_object_handlers *handlers;
                      zend_uint refcount;
                      gc_root_buffer *buffered;
                  } obj;
                  struct {
                      int next;
                  } free_list;
              } bucket;
          } zend_object_store_bucket;
        • 向对象池中添加对象, 本处仅从调用点开始分析, 对于怎么走到调用点的部分放到以后的语法分析和词法分析再来补充

          • 各调用点调用 object_init, object_init_ex 等函数最终调用_object_and_properties_init

            • // 初始化对象
              ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties ZEND_FILE_LINE_DC TSRMLS_DC)
              {
                  zend_object *object;
                  // 经过类信息初始化对象
                  if (class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
                      char *what = (class_type->ce_flags & ZEND_ACC_INTERFACE) ? "interface" :((class_type->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) ? "trait" :                                                      "abstract class";
                      zend_error(E_ERROR, "Cannot instantiate %s %s", what, class_type->name);
                  }
              
                  zend_update_class_constants(class_type TSRMLS_CC);
              
                  Z_TYPE_P(arg) = IS_OBJECT;
                  if (class_type->create_object == NULL) {
                      // 调用 zend_objects_new 实例化对象
                      Z_OBJVAL_P(arg) = zend_objects_new(&object, class_type TSRMLS_CC);
                      if (properties) {
                          object->properties = properties;
                          object->properties_table = NULL;
                      } else {
                          object_properties_init(object, class_type);
                      }
                  } else {
                      Z_OBJVAL_P(arg) = class_type->create_object(class_type TSRMLS_CC);
                  }
                  return SUCCESS;
              }
          • 调用 zend_objects_new 建立对象

            • // 建立对象, 放入对象池中
              // 注意 zend_object 结构
              ZEND_API zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class_type TSRMLS_DC)
              {
                  zend_object_value retval;
              
                  *object = emalloc(sizeof(zend_object));
                  (*object)->ce = class_type;
                  (*object)->properties = NULL;
                  (*object)->properties_table = NULL;
                  (*object)->guards = NULL;
                  // 将 zend_object 结构对象存储到对象池中
                  retval.handle = zend_objects_store_put(*object, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) zend_objects_free_object_storage, NULL TSRMLS_CC);
                  retval.handlers = &std_object_handlers;
                  return retval;
              }
              • zend_object 结构, 是从调用点通过对 zval 通过一些处理获得的结构, 而后再将其进一步封装成 zend_object_value, 存入对象池

                • zend_object 结构

                  // 最终存储在对象哈希表中的对象结构
                  typedef struct _zend_object {
                      // 对象的类信息
                      zend_class_entry *ce;
                      // 属性信息
                      HashTable *properties;
                      zval **properties_table;
                      HashTable *guards; /* protects from __get/__set ... recursion */
                  } zend_object;
                • 调用 zend_objects_store_put 函数, 设置对象的值, 存入对象池中

                  // 将对象存入对象池
                  ZEND_API zend_object_handle zend_objects_store_put(void *object, zend_objects_store_dtor_t dtor, zend_objects_free_object_storage_t free_storage, zend_objects_store_clone_t clone TSRMLS_DC)
                  {
                      zend_object_handle handle;
                      struct _store_object *obj;
                  
                      if (EG(objects_store).free_list_head != -1) {
                          handle = EG(objects_store).free_list_head;
                          EG(objects_store).free_list_head = EG(objects_store).object_buckets[handle].bucket.free_list.next;
                      } else {
                          if (EG(objects_store).top == EG(objects_store).size) {
                              EG(objects_store).size <<= 1;
                              EG(objects_store).object_buckets = (zend_object_store_bucket *) erealloc(EG(objects_store).object_buckets, EG(objects_store).size * sizeof(zend_object_store_bucket));
                          }
                          handle = EG(objects_store).top++;
                      }
                      // 设置对象池中新节点的值
                      obj = &EG(objects_store).object_buckets[handle].bucket.obj;
                      EG(objects_store).object_buckets[handle].destructor_called = 0;
                      EG(objects_store).object_buckets[handle].valid = 1;
                      EG(objects_store).object_buckets[handle].apply_count = 0;
                  
                      obj->refcount = 1;
                      GC_OBJ_INIT(obj);
                      // 将 zend_object 结构的对象存入 object 属性
                      obj->object = object;
                      obj->dtor = dtor?dtor:(zend_objects_store_dtor_t)zend_objects_destroy_object;
                      obj->free_storage = free_storage;
                      obj->clone = clone;
                      obj->handlers = NULL;
                  
                  #if ZEND_DEBUG_OBJECTS
                      fprintf(stderr, "Allocated object id #%d\n", handle);
                  #endif
                      return handle;
                  }
    • 对象方法

      struct _zend_object_handlers {
          /* general object functions */
          zend_object_add_ref_t                   add_ref;
          zend_object_del_ref_t                   del_ref;
          zend_object_clone_obj_t                 clone_obj;
          /* individual object functions */
          zend_object_read_property_t             read_property;
          zend_object_write_property_t            write_property;
          zend_object_read_dimension_t            read_dimension;
          zend_object_write_dimension_t           write_dimension;
          zend_object_get_property_ptr_ptr_t      get_property_ptr_ptr;
          zend_object_get_t                       get;
          zend_object_set_t                       set;
          zend_object_has_property_t              has_property;
          zend_object_unset_property_t            unset_property;
          zend_object_has_dimension_t             has_dimension;
          zend_object_unset_dimension_t           unset_dimension;
          zend_object_get_properties_t            get_properties;
          zend_object_get_method_t                get_method;
          zend_object_call_method_t               call_method;
          zend_object_get_constructor_t           get_constructor;
          zend_object_get_class_entry_t           get_class_entry;
          zend_object_get_class_name_t            get_class_name;
          zend_object_compare_t                   compare_objects;
          zend_object_cast_t                      cast_object;
          zend_object_count_elements_t            count_elements;
          zend_object_get_debug_info_t            get_debug_info;
          zend_object_get_closure_t               get_closure;
          zend_object_get_gc_t                    get_gc;
      };
      • 仍是拿以前强制类型转换为例

        • // 打印 zval 值
          ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_copy)
          {
              if (Z_TYPE_P(expr)==IS_STRING) {
                  *use_copy = 0;
                  return;
              }
              switch (Z_TYPE_P(expr)) {
                  case IS_NULL:
                      Z_STRLEN_P(expr_copy) = 0;
                      Z_STRVAL_P(expr_copy) = STR_EMPTY_ALLOC();
                      break;
          
                  // 省略 ...
          
                  case IS_OBJECT:
                      {
                          TSRMLS_FETCH();
                          // 直接转换成字符串, zend_std_cast_object_tostring, 调用 tostring
                          if (zend_std_cast_object_tostring(expr, expr_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
                              break;
                          }
                          // 是否认义了 cast_object 函数
                          if (Z_OBJ_HANDLER_P(expr, cast_object)) {
                              zval *val;
          
                              ALLOC_ZVAL(val);
                              INIT_PZVAL_COPY(val, expr);
                              zval_copy_ctor(val);
                              // 调用转换函数
                              if (Z_OBJ_HANDLER_P(expr, cast_object)(val, expr_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
                                  zval_ptr_dtor(&val);
                                  break;
                              }
                              zval_ptr_dtor(&val);
                          }
                          // 是否认义了 get 函数
                          if (!Z_OBJ_HANDLER_P(expr, cast_object) && Z_OBJ_HANDLER_P(expr, get)) {
                              zval *z = Z_OBJ_HANDLER_P(expr, get)(expr TSRMLS_CC);
          
                              Z_ADDREF_P(z);
                              if (Z_TYPE_P(z) != IS_OBJECT) {
                                  zend_make_printable_zval(z, expr_copy, use_copy);
                                  if (*use_copy) {
                                      zval_ptr_dtor(&z);
                                  } else {
                                      ZVAL_ZVAL(expr_copy, z, 0, 1);
                                      *use_copy = 1;
                                  }
                                  return;
                              }
                              zval_ptr_dtor(&z);
                          }
          
                          // 省略 ...
          }

总结

php 内核对于对象的管理是经过对象池 object_store 这么个东西

对象池中的节点并无直接存 zval 结构, 而是将 zval 包装成 zend_object 结构, 再存入 object_store.object_buckets[handle].bucket.obj.object 中

object_store api (Zend/zend_objects_API.c)

函数 做用 备注
zend_objects_store_init 对象池的初始化 ZEND_API void zend_objects_store_init(zend_objects_store *objects, zend_uint init_size)
zend_objects_store_destroy 对象池的销毁 ZEND_API void zend_objects_store_destroy(zend_objects_store *objects)
zend_objects_store_call_destructors 对象池中的对象释放 ZEND_API void zend_objects_store_call_destructors(zend_objects_store *objects TSRMLS_DC)
zend_objects_store_mark_destructed 标记对象池中待销毁的对象 ZEND_API void zend_objects_store_mark_destructed(zend_objects_store *objects TSRMLS_DC)
zend_objects_store_free_object_storage 释放对象池中的全部对象 ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects TSRMLS_DC)
zend_objects_store_put 将对象存储到对象池中 ZEND_API zend_object_handle zend_objects_store_put(void *object, zend_objects_store_dtor_t dtor, zend_objects_free_object_storage_t free_storage, zend_objects_store_clone_t clone TSRMLS_DC)
zend_objects_store_get_refcount 获取对象池中指定 zval 对象的 refcount 值 ZEND_API zend_uint zend_objects_store_get_refcount(zval *object TSRMLS_DC)
zend_objects_store_add_ref 增长对象池中指定 zval 对象的 refcount 值, +1 ZEND_API void zend_objects_store_add_ref(zval *object TSRMLS_DC)
zend_objects_store_add_ref_by_handle 经过索引 handle 增长对象的 refcount, +1 ZEND_API void zend_objects_store_add_ref_by_handle(zend_object_handle handle TSRMLS_DC)
zend_objects_store_del_ref 从对象池中删除指定 zval 的对象的 refcount, -1 ZEND_API void zend_objects_store_del_ref_by_handle_ex(zend_object_handle handle, const zend_object_handlers *handlers TSRMLS_DC)
zend_objects_store_clone_obj 克隆对象 ZEND_API zend_object_value zend_objects_store_clone_obj(zval *zobject TSRMLS_DC)
zend_object_store_get_object 从对象池中获取对象的值 ZEND_API void zend_object_store_get_object(const zval zobject TSRMLS_DC)
zend_object_store_get_object_by_handle 经过索引 handle 获取对象 ZEND_API void *zend_object_store_get_object_by_handle(zend_object_handle handle TSRMLS_DC)
zend_object_store_ctor_failed 当建立对象发生异常时调用的函数 ZEND_API void zend_object_store_ctor_failed(zval *zobject TSRMLS_DC)
相关文章
相关标签/搜索