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)
相關文章
相關標籤/搜索