php object 对象系统

php object 对象系统

概述

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

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

php 将所有执行过程中的 object 放在一个对象池中进行管理 EG(objects_store)

结构

  • zval 结构 (Zend/zend.h)

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

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

        • // 运行时的全局数据
          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)

        • // 对象池, 存放 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)
上一篇:java编程如何实现多条2017-01-16 22:28:11.0这样的时间数据,转换成Date类型Mon Jan 16 22:28:11 CST 2017这样的时间数据


下一篇:微软必应·英雄会第三届在线编程大赛:几个bing?