• [php-src]窥探Php内核中的数组与面向对象


    内容均以php5.6.14为例.

    扩展中定义一个类有以下四步:

    #1. 声明一个存储类信息的指针.
    
      zend_class_entry *errs_ce;
    
    #2. 定义方法的参数信息,类的方法实现.
    
      ZEND_BEGIN_ARG_INFO_EX(errs_test_arginfo, 0, 0, 1)
          ZEND_ARG_INFO(0, arg)
      ZEND_END_ARG_INFO()
    
      PHP_METHOD(errs, test) {
      }
    
    #3. 声明一个含有类方法信息的数组; 统一用含有三个NULL的数组结尾.
    
      zend_function_entry errs_methods[] = {
          PHP_ME(errs, test, errs_test_arginfo, ZEND_ACC_PUBLIC)
          {NULL, NULL, NULL}
      }; /* 注意 errs_methods 结尾要加分号。 */
    
    #4. 模块初始化 MINIT 中注册.
    
      PHP_MINIT_FUNCTION(testmodule)
      {
          zend_class_entry ce;
        /* init class entry */ INIT_CLASS_ENTRY(ce,
    "errs", errs_methods);
        /* register */ errs_ce
    = zend_register_internal_class(&ce TSRMLS_CC);
        /* flags */ errs_ce
    ->ce_flags |= ZEND_ACC_FINAL_CLASS; return SUCCESS; }

    zend_class_entry 是实现PHP类和对象的基础结构类型。

    ./Zend/zend.h:302

    /*
     * zval
     */
    typedef struct _zend_class_entry zend_class_entry;
    
    ....
    
    struct _zend_class_entry {
        char type;
        const char *name;
        zend_uint name_length;
        struct _zend_class_entry *parent;
        int refcount;
        zend_uint ce_flags;
    
        HashTable function_table;
        HashTable properties_info;
        zval **default_properties_table;
        zval **default_static_members_table;
        zval **static_members_table;
        HashTable constants_table;
        int default_properties_count;
        int default_static_members_count;
    
        union _zend_function *constructor;
        union _zend_function *destructor;
        union _zend_function *clone;
        union _zend_function *__get;
        union _zend_function *__set;
        union _zend_function *__unset;
        union _zend_function *__isset;
        union _zend_function *__call;
        union _zend_function *__callstatic;
        union _zend_function *__tostring;
        union _zend_function *__debugInfo;
        union _zend_function *serialize_func;
        union _zend_function *unserialize_func;
    
        zend_class_iterator_funcs iterator_funcs;
    
        /* handlers */
        zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
        zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
        int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
        union _zend_function *(*get_static_method)(zend_class_entry *ce, char* method, int method_len TSRMLS_DC);
    
        /* serializer callbacks */
        int (*serialize)(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
        int (*unserialize)(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);
    
        zend_class_entry **interfaces;
        zend_uint num_interfaces;
    
        zend_class_entry **traits;
        zend_uint num_traits;
        zend_trait_alias **trait_aliases;
        zend_trait_precedence **trait_precedences;
    
        union {
            struct {
                const char *filename;
                zend_uint line_start;
                zend_uint line_end;
                const char *doc_comment;
                zend_uint doc_comment_len;
            } user;
            struct {
                const struct _zend_function_entry *builtin_functions;
                struct _zend_module_entry *module;
            } internal;
        } info;
    };

    定义参数信息的宏。

    ./Zend/zend_API.h:108

    #define ZEND_ARG_INFO(pass_by_ref, name)    { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref, 0, 0 },
    
    ...
    #define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) static const zend_arg_info name[] = { { NULL, 0, NULL, required_num_args, 0, return_reference, 0, 0 }, #define ZEND_BEGIN_ARG_INFO(name, _unused) ZEND_BEGIN_ARG_INFO_EX(name, 0, ZEND_RETURN_VALUE, -1) #define ZEND_END_ARG_INFO() };

      ZEND_BEGIN_ARG_INFO_EX() 的四个参数含义:

      name: 类名_方法名_arginfo

      _unused: 0

      return_reference: 0

      required_num_args: 这个函数必要的参数数量是几个

      ZEND_ARG_INFO() 的两个参数含义:

         pass_by_ref: 0

         name: 形参名

    ./Zend/zend_API.h:35

    typedef struct _zend_function_entry {
        const char *fname;
        void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
        const struct _zend_arg_info *arg_info;
        zend_uint num_args;
        zend_uint flags;
    } zend_function_entry;
    #define INIT_CLASS_ENTRY(class_container, class_name, functions) 
        INIT_OVERLOADED_CLASS_ENTRY(class_container, class_name, functions, NULL, NULL, NULL)
    
    #define INIT_CLASS_ENTRY_EX(class_container, class_name, class_name_len, functions) 
        INIT_OVERLOADED_CLASS_ENTRY_EX(class_container, class_name, class_name_len, functions, NULL, NULL, NULL, NULL, NULL)
    
    #define INIT_OVERLOADED_CLASS_ENTRY_EX(class_container, class_name, class_name_len, functions, handle_fcall, handle_propget,  handle_propset, handle_propunset, handle_propisset) 
        {                                                           
            const char *cl_name = class_name;                               
            int _len = class_name_len;                              
            class_container.name = zend_new_interned_string(cl_name, _len+1, 0 TSRMLS_CC);  
            if (class_container.name == cl_name) {                  
                class_container.name = zend_strndup(cl_name, _len); 
            }                                                       
            class_container.name_length = _len;                     
            INIT_CLASS_ENTRY_INIT_METHODS(class_container, functions, handle_fcall, handle_propget, handle_propset,               handle_propunset, handle_propisset) 
        }
    ....
    
    #define INIT_OVERLOADED_CLASS_ENTRY(class_container, class_name, functions, handle_fcall, handle_propget, handle_propset) 
        INIT_OVERLOADED_CLASS_ENTRY_EX(class_container, class_name, sizeof(class_name)-1, functions, handle_fcall,                handle_propget, handle_propset, NULL, NULL)

    类的定义,接口定义,属性操作,数组操作的函数原型。

    ./Zend/zend_API.h: 268~457

    ....
    
    ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC);
    ZEND_API void zend_unregister_functions(const zend_function_entry *functions, int count, HashTable *function_table TSRMLS_DC);
    ZEND_API int zend_startup_module(zend_module_entry *module_entry);
    ZEND_API zend_module_entry* zend_register_internal_module(zend_module_entry *module_entry TSRMLS_DC);
    ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module TSRMLS_DC);
    ZEND_API int zend_startup_module_ex(zend_module_entry *module TSRMLS_DC);
    ZEND_API int zend_startup_modules(TSRMLS_D);
    ZEND_API void zend_collect_module_handlers(TSRMLS_D);
    ZEND_API void zend_destroy_modules(void);
    ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, int error_type TSRMLS_DC);
    
    // 注册一个"类"
    ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *class_entry TSRMLS_DC);
    
    // 注册一个"子类";第二个,第三个参数都为 NULL 时,等同于 zend_register_internal_class. ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce, char *parent_name TSRMLS_DC);
    // 注册一个"接口" ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *orig_class_entry TSRMLS_DC); ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int num_interfaces, ...); ZEND_API int zend_register_class_alias_ex(const char *name, int name_len, zend_class_entry *ce TSRMLS_DC); #define zend_register_class_alias(name, ce) zend_register_class_alias_ex(name, sizeof(name)-1, ce TSRMLS_CC) #define zend_register_ns_class_alias(ns, name, ce) zend_register_class_alias_ex(ZEND_NS_NAME(ns, name), sizeof(ZEND_NS_NAME(ns, name))-1, ce TSRMLS_CC) ZEND_API int zend_disable_function(char *function_name, uint function_name_length TSRMLS_DC); ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_DC); ZEND_API void zend_wrong_param_count(TSRMLS_D); #define IS_CALLABLE_CHECK_SYNTAX_ONLY (1<<0) #define IS_CALLABLE_CHECK_NO_ACCESS (1<<1) #define IS_CALLABLE_CHECK_IS_STATIC (1<<2) #define IS_CALLABLE_CHECK_SILENT (1<<3) #define IS_CALLABLE_STRICT (IS_CALLABLE_CHECK_IS_STATIC) ZEND_API zend_bool zend_is_callable_ex(zval *callable, zval *object_ptr, uint check_flags, char **callable_name, int *callable_name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC); ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name TSRMLS_DC); ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRMLS_DC); ZEND_API const char *zend_get_module_version(const char *module_name); ZEND_API int zend_get_module_started(const char *module_name); ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type TSRMLS_DC); ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type, const char *doc_comment, int doc_comment_len TSRMLS_DC);
    // 定义类属性,zend_declare_property_* ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, int name_length, int access_type TSRMLS_DC); ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, int name_length, long value, int access_type TSRMLS_DC); ZEND_API int zend_declare_property_long(zend_class_entry *ce, const char *name, int name_length, long value, int access_type TSRMLS_DC); ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name, int name_length, double value, int access_type TSRMLS_DC); ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, int name_length, const char *value, int access_type TSRMLS_DC); ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, int name_length, const char *value, int value_len, int access_type TSRMLS_DC); // 定义类常量,zend_declare_class_constant_* ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value TSRMLS_DC); ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length TSRMLS_DC); ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, long value TSRMLS_DC); ZEND_API int zend_declare_class_constant_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_bool value TSRMLS_DC); ZEND_API int zend_declare_class_constant_double(zend_class_entry *ce, const char *name, size_t name_length, double value TSRMLS_DC); ZEND_API int zend_declare_class_constant_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_length TSRMLS_DC); ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value TSRMLS_DC); // 更新类常量,zend_update_class_constants_* ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC); ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const char *name, int name_length, zval *value TSRMLS_DC); ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, const char *name, int name_length TSRMLS_DC); ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, const char *name, int name_length, long value TSRMLS_DC); ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, const char *name, int name_length, long value TSRMLS_DC); ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, const char *name, int name_length, double value TSRMLS_DC); ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, const char *name, int name_length, const char *value TSRMLS_DC); ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, const char *name, int name_length, const char *value, int value_length TSRMLS_DC); // 更新类静态属性,zend_update_static_property_* ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *name, int name_length, zval *value TSRMLS_DC); ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const char *name, int name_length TSRMLS_DC); ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const char *name, int name_length, long value TSRMLS_DC); ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const char *name, int name_length, long value TSRMLS_DC); ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const char *name, int name_length, double value TSRMLS_DC); ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const char *name, int name_length, const char *value TSRMLS_DC); ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const char *name, int name_length, const char *value, int value_length TSRMLS_DC); // 读取类属性 ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_bool silent TSRMLS_DC); // 读取类静态属性,与object无关 ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, int name_length, zend_bool silent TSRMLS_DC); ZEND_API zend_class_entry *zend_get_class_entry(const zval *zobject TSRMLS_DC); ZEND_API int zend_get_object_classname(const zval *object, const char **class_name, zend_uint *class_name_len TSRMLS_DC); ZEND_API char *zend_get_type_by_const(int type); #define getThis() (this_ptr) #define WRONG_PARAM_COUNT ZEND_WRONG_PARAM_COUNT() #define WRONG_PARAM_COUNT_WITH_RETVAL(ret) ZEND_WRONG_PARAM_COUNT_WITH_RETVAL(ret) #define ARG_COUNT(dummy) (ht) #define ZEND_NUM_ARGS() (ht) #define ZEND_WRONG_PARAM_COUNT() { zend_wrong_param_count(TSRMLS_C); return; } #define ZEND_WRONG_PARAM_COUNT_WITH_RETVAL(ret) { zend_wrong_param_count(TSRMLS_C); return ret; } #ifndef ZEND_WIN32 #define DLEXPORT #endif // 初始化一个数组 #define array_init(arg) _array_init((arg), 0 ZEND_FILE_LINE_CC) #define array_init_size(arg, size) _array_init((arg), (size) ZEND_FILE_LINE_CC) // 初始化一个对象 #define object_init(arg) _object_init((arg) ZEND_FILE_LINE_CC TSRMLS_CC) #define object_init_ex(arg, ce) _object_init_ex((arg), (ce) ZEND_FILE_LINE_CC TSRMLS_CC) #define object_and_properties_init(arg, ce, properties) _object_and_properties_init((arg), (ce), (properties) ZEND_FILE_LINE_CC TSRMLS_CC) ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC); ZEND_API int _object_init(zval *arg ZEND_FILE_LINE_DC TSRMLS_DC); ZEND_API int _object_init_ex(zval *arg, zend_class_entry *ce ZEND_FILE_LINE_DC TSRMLS_DC); ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties ZEND_FILE_LINE_DC TSRMLS_DC); ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type); ZEND_API void zend_merge_properties(zval *obj, HashTable *properties, int destroy_ht TSRMLS_DC); /* no longer supported */ ZEND_API int add_assoc_function(zval *arg, const char *key, void (*function_ptr)(INTERNAL_FUNCTION_PARAMETERS)); ZEND_API int add_assoc_long_ex(zval *arg, const char *key, uint key_len, long n); ZEND_API int add_assoc_null_ex(zval *arg, const char *key, uint key_len); ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, uint key_len, int b); ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, uint key_len, int r); ZEND_API int add_assoc_double_ex(zval *arg, const char *key, uint key_len, double d); ZEND_API int add_assoc_string_ex(zval *arg, const char *key, uint key_len, char *str, int duplicate); ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, uint key_len, char *str, uint length, int duplicate); ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, uint key_len, zval *value); // 添加关联数组值,add_assoc_* #define add_assoc_long(__arg, __key, __n) add_assoc_long_ex(__arg, __key, strlen(__key)+1, __n) #define add_assoc_null(__arg, __key) add_assoc_null_ex(__arg, __key, strlen(__key) + 1) #define add_assoc_bool(__arg, __key, __b) add_assoc_bool_ex(__arg, __key, strlen(__key)+1, __b) #define add_assoc_resource(__arg, __key, __r) add_assoc_resource_ex(__arg, __key, strlen(__key)+1, __r) #define add_assoc_double(__arg, __key, __d) add_assoc_double_ex(__arg, __key, strlen(__key)+1, __d) #define add_assoc_string(__arg, __key, __str, __duplicate) add_assoc_string_ex(__arg, __key, strlen(__key)+1, __str, __duplicate) #define add_assoc_stringl(__arg, __key, __str, __length, __duplicate) add_assoc_stringl_ex(__arg, __key, strlen(__key)+1, __str, __length, __duplicate) #define add_assoc_zval(__arg, __key, __value) add_assoc_zval_ex(__arg, __key, strlen(__key)+1, __value) /* unset() functions are only suported for legacy modules and null() functions should be used */ #define add_assoc_unset(__arg, __key) add_assoc_null_ex(__arg, __key, strlen(__key) + 1) #define add_index_unset(__arg, __key) add_index_null(__arg, __key) #define add_next_index_unset(__arg) add_next_index_null(__arg) #define add_property_unset(__arg, __key) add_property_null(__arg, __key) // 添加索引数组值,add_index_* ZEND_API int add_index_long(zval *arg, ulong idx, long n); ZEND_API int add_index_null(zval *arg, ulong idx); ZEND_API int add_index_bool(zval *arg, ulong idx, int b); ZEND_API int add_index_resource(zval *arg, ulong idx, int r); ZEND_API int add_index_double(zval *arg, ulong idx, double d); ZEND_API int add_index_string(zval *arg, ulong idx, const char *str, int duplicate); ZEND_API int add_index_stringl(zval *arg, ulong idx, const char *str, uint length, int duplicate); ZEND_API int add_index_zval(zval *arg, ulong index, zval *value); // 添加索引数组值 索引自增,add_next_index_* ZEND_API int add_next_index_long(zval *arg, long n); ZEND_API int add_next_index_null(zval *arg); ZEND_API int add_next_index_bool(zval *arg, int b); ZEND_API int add_next_index_resource(zval *arg, int r); ZEND_API int add_next_index_double(zval *arg, double d); ZEND_API int add_next_index_string(zval *arg, const char *str, int duplicate); ZEND_API int add_next_index_stringl(zval *arg, const char *str, uint length, int duplicate); ZEND_API int add_next_index_zval(zval *arg, zval *value); ZEND_API int add_get_assoc_string_ex(zval *arg, const char *key, uint key_len, const char *str, void **dest, int duplicate); ZEND_API int add_get_assoc_stringl_ex(zval *arg, const char *key, uint key_len, const char *str, uint length, void **dest, int duplicate); #define add_get_assoc_string(__arg, __key, __str, __dest, __duplicate) add_get_assoc_string_ex(__arg, __key, strlen(__key)+1, __str, __dest, __duplicate) #define add_get_assoc_stringl(__arg, __key, __str, __length, __dest, __duplicate) add_get_assoc_stringl_ex(__arg, __key, strlen(__key)+1, __str, __length, __dest, __duplicate) ZEND_API int add_get_index_long(zval *arg, ulong idx, long l, void **dest); ZEND_API int add_get_index_double(zval *arg, ulong idx, double d, void **dest); ZEND_API int add_get_index_string(zval *arg, ulong idx, const char *str, void **dest, int duplicate); ZEND_API int add_get_index_stringl(zval *arg, ulong idx, const char *str, uint length, void **dest, int duplicate); ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value); ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, long l TSRMLS_DC); ZEND_API int add_property_null_ex(zval *arg, const char *key, uint key_len TSRMLS_DC); ZEND_API int add_property_bool_ex(zval *arg, const char *key, uint key_len, int b TSRMLS_DC); ZEND_API int add_property_resource_ex(zval *arg, const char *key, uint key_len, long r TSRMLS_DC); ZEND_API int add_property_double_ex(zval *arg, const char *key, uint key_len, double d TSRMLS_DC); ZEND_API int add_property_string_ex(zval *arg, const char *key, uint key_len, const char *str, int duplicate TSRMLS_DC); ZEND_API int add_property_stringl_ex(zval *arg, const char *key, uint key_len, const char *str, uint length, int duplicate TSRMLS_DC); ZEND_API int add_property_zval_ex(zval *arg, const char *key, uint key_len, zval *value TSRMLS_DC); // 添加类属性 add_property_* #define add_property_long(__arg, __key, __n) add_property_long_ex(__arg, __key, strlen(__key)+1, __n TSRMLS_CC) #define add_property_null(__arg, __key) add_property_null_ex(__arg, __key, strlen(__key) + 1 TSRMLS_CC) #define add_property_bool(__arg, __key, __b) add_property_bool_ex(__arg, __key, strlen(__key)+1, __b TSRMLS_CC) #define add_property_resource(__arg, __key, __r) add_property_resource_ex(__arg, __key, strlen(__key)+1, __r TSRMLS_CC) #define add_property_double(__arg, __key, __d) add_property_double_ex(__arg, __key, strlen(__key)+1, __d TSRMLS_CC) #define add_property_string(__arg, __key, __str, __duplicate) add_property_string_ex(__arg, __key, strlen(__key)+1, __str, __duplicate TSRMLS_CC) #define add_property_stringl(__arg, __key, __str, __length, __duplicate) add_property_stringl_ex(__arg, __key, strlen(__key)+1, __str, __length, __duplicate TSRMLS_CC) #define add_property_zval(__arg, __key, __value) add_property_zval_ex(__arg, __key, strlen(__key)+1, __value TSRMLS_CC) // call_user_function ZEND_API int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC); ZEND_API int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, zend_uint param_count, zval ** params[], int no_separation, HashTable *symbol_table TSRMLS_DC); ZEND_API extern const zend_fcall_info empty_fcall_info; ZEND_API extern const zend_fcall_info_cache empty_fcall_info_cache; ....

    关于 zend_read_static_property 的 silent 参数,因为是 zend_std_get_static_property 的封装,

    所以我们应该看 zend_std_get_static_property 的实现。

    ./Zend/zend_object_handlers.c:1281

            if (UNEXPECTED(zend_hash_quick_find(&ce->properties_info, property_name, property_name_len+1, hash_value, (void **) &property_info)==FAILURE)) {
                if (!silent) {
                    zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
                }
                return NULL;
            } 

    函数中有这么一段,如果没有找到属性的时候,silent=0 报 E_ERROR,silent=1 忽略报错。

    HashTable 的底层函数,数组操作其实是对它们的再封装。

    ./Zend/zend_hash.h:100

    /* startup/shutdown */
    ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC);
    ZEND_API int _zend_hash_init_ex(HashTable *ht, uint nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC);
    ZEND_API void zend_hash_destroy(HashTable *ht);
    ZEND_API void zend_hash_clean(HashTable *ht);
    #define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent) _zend_hash_init((ht), (nSize), (pDestructor), (persistent) ZEND_FILE_LINE_CC)
    #define zend_hash_init_ex(ht, nSize, pHashFunction, pDestructor, persistent, bApplyProtection) _zend_hash_init_ex((ht), (nSize), (pDestructor), (persistent), (bApplyProtection) ZEND_FILE_LINE_CC)
    
    /* additions/updates/changes */
    ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC);
    #define zend_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest) 
            _zend_hash_add_or_update(ht, arKey, nKeyLength, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC)
    #define zend_hash_add(ht, arKey, nKeyLength, pData, nDataSize, pDest) 
            _zend_hash_add_or_update(ht, arKey, nKeyLength, pData, nDataSize, pDest, HASH_ADD ZEND_FILE_LINE_CC)
    
    ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC);
    #define zend_hash_quick_update(ht, arKey, nKeyLength, h, pData, nDataSize, pDest) 
            _zend_hash_quick_add_or_update(ht, arKey, nKeyLength, h, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC)
    #define zend_hash_quick_add(ht, arKey, nKeyLength, h, pData, nDataSize, pDest) 
            _zend_hash_quick_add_or_update(ht, arKey, nKeyLength, h, pData, nDataSize, pDest, HASH_ADD ZEND_FILE_LINE_CC)
    
    ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC);
    #define zend_hash_index_update(ht, h, pData, nDataSize, pDest) 
            _zend_hash_index_update_or_next_insert(ht, h, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC)
    #define zend_hash_next_index_insert(ht, pData, nDataSize, pDest) 
            _zend_hash_index_update_or_next_insert(ht, 0, pData, nDataSize, pDest, HASH_NEXT_INSERT ZEND_FILE_LINE_CC)
    
    ZEND_API int zend_hash_add_empty_element(HashTable *ht, const char *arKey, uint nKeyLength);
    
    ....
    
    /* Deletes */
    ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, int flag);
    #define zend_hash_del(ht, arKey, nKeyLength) 
            zend_hash_del_key_or_index(ht, arKey, nKeyLength, 0, HASH_DEL_KEY)
    #define zend_hash_quick_del(ht, arKey, nKeyLength, h) 
            zend_hash_del_key_or_index(ht, arKey, nKeyLength, h, HASH_DEL_KEY_QUICK)
    #define zend_hash_index_del(ht, h) 
            zend_hash_del_key_or_index(ht, NULL, 0, h, HASH_DEL_INDEX)
    #define zend_get_hash_value 
            zend_hash_func
    
    /* Data retreival */
    ZEND_API int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData);
    ZEND_API int zend_hash_quick_find(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void **  pData);
    ZEND_API int zend_hash_index_find(const HashTable *ht, ulong h, void **pData);
    
    /* Misc */
    ZEND_API int zend_hash_exists(const HashTable *ht, const char *arKey, uint nKeyLength);
    ZEND_API int zend_hash_quick_exists(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h);
    ZEND_API int zend_hash_index_exists(const HashTable *ht, ulong h);
    ZEND_API ulong zend_hash_next_free_element(const HashTable *ht);

    类与方法的访问权限修饰符,ZEND_ACC_* 。

    ./Zend/zend_compile.h:150

    ...
    
    /* method flags (types) */
    #define ZEND_ACC_STATIC         0x01
    #define ZEND_ACC_ABSTRACT       0x02
    #define ZEND_ACC_FINAL          0x04
    #define ZEND_ACC_IMPLEMENTED_ABSTRACT       0x08
    
    /* class flags (types) */
    /* ZEND_ACC_IMPLICIT_ABSTRACT_CLASS is used for abstract classes (since it is set by any abstract method even interfaces MAY have it set, too). */
    /* ZEND_ACC_EXPLICIT_ABSTRACT_CLASS denotes that a class was explicitly defined as abstract by using the keyword. */
    #define ZEND_ACC_IMPLICIT_ABSTRACT_CLASS    0x10
    #define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS    0x20
    #define ZEND_ACC_FINAL_CLASS                0x40
    #define ZEND_ACC_INTERFACE                  0x80
    #define ZEND_ACC_TRAIT                      0x120
    
    /* op_array flags */
    #define ZEND_ACC_INTERACTIVE                0x10
    
    /* method flags (visibility) */
    /* The order of those must be kept - public < protected < private */
    #define ZEND_ACC_PUBLIC     0x100
    #define ZEND_ACC_PROTECTED  0x200
    #define ZEND_ACC_PRIVATE    0x400
    #define ZEND_ACC_PPP_MASK  (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE)
    
    #define ZEND_ACC_CHANGED    0x800
    #define ZEND_ACC_IMPLICIT_PUBLIC    0x1000
    
    /* method flags (special method detection) */
    #define ZEND_ACC_CTOR       0x2000
    #define ZEND_ACC_DTOR       0x4000
    #define ZEND_ACC_CLONE      0x8000
    
    /* method flag (bc only), any method that has this flag can be used statically and non statically. */
    #define ZEND_ACC_ALLOW_STATIC   0x10000
    
    /* shadow of parent's private method/property */
    #define ZEND_ACC_SHADOW 0x20000
    
    /* deprecation flag */
    #define ZEND_ACC_DEPRECATED 0x40000
    
    /* class implement interface(s) flag */
    #define ZEND_ACC_IMPLEMENT_INTERFACES 0x80000
    #define ZEND_ACC_IMPLEMENT_TRAITS     0x400000
    
    /* class constants updated */
    #define ZEND_ACC_CONSTANTS_UPDATED    0x100000
    
    /* user class has methods with static variables */
    #define ZEND_HAS_STATIC_IN_METHODS    0x800000
    
    
    #define ZEND_ACC_CLOSURE              0x100000
    #define ZEND_ACC_GENERATOR            0x800000
    
    /* function flag for internal user call handlers __call, __callstatic */
    #define ZEND_ACC_CALL_VIA_HANDLER     0x200000
    
    /* disable inline caching */
    #define ZEND_ACC_NEVER_CACHE          0x400000
    
    #define ZEND_ACC_VARIADIC               0x1000000
    
    #define ZEND_ACC_RETURN_REFERENCE       0x4000000
    #define ZEND_ACC_DONE_PASS_TWO          0x8000000
    
    /* function has arguments with type hinting */
    #define ZEND_ACC_HAS_TYPE_HINTS         0x10000000
    
    ...

    例:定义一个接口,实现接口的父类,继承父类的子类.

    zend_class_entry *theinterface_ce, *parentclass_ce, *childclass_ce;
    
    zend_function_entry theinterface_methods[] = {
      ZEND_ABSTRACT_ME(theinterface, hello, NULL)   // 这里不需要第四个参数(访问权限)
      {NULL, NULL, NULL}
    };
    
    zend_function_entry parentclass_methods[] = {
       ZEND_ME(parentclass_ce, hello, NULL, ZEND_ACC_PUBLIC)
      {NULL, NULL, NULL}
    };
    
    zend_function_entry childclass_methods[] = {
      ZEND_ME(childclass_ce, index, NULL, ZEND_ACC_PUBLIC)
      {NULL, NULL, NULL}
    };
    
    PHP_MINIT_FUNCTION(test) {
      zend_class_entry ce, p_ce, c_ce;
      INIT_CLASS_ENTRY(ce, "theinterface", theinterface_methods);
      theinterface_ce = zend_register_internal_interface(&ce TSRMLS_CC);
    
       // 实现theinterface接口的parentclass类
      INIT_CLASS_ENTRY(p_ce, "parentclass", parentclass_methods);
      parentclass_ce = zend_register_internal_class(&p_ce TSRMLS_CC);
      zend_class_implements(&p_ce TSRMLS_CC, 1, theinterface_ce);
    
       // 定义parentclass的子类childclass
      INIT_CLASS_ENTRY(c_ce, "childclass", childclass_methods);
      childclass_ce = zend_register_internal_class_ex(&c_ce, &parentclass, "parentclass" TSRMLS_CC);
      childclass_cd->ce_flags |= ZEND_ACC_FINAL_CLASS;
      
      return SUCCESS;
    }

    ./Zend/zend_API.h 包含使用到的宏和函数原型,主要看有哪些参数和参数格式:

    #define ZEND_ABSTRACT_ME(classname, name, arg_info) ZEND_FENTRY(name, NULL, arg_info, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
    #define ZEND_ME(classname, name, arg_info, flags) ZEND_FENTRY(name, ZEND_MN(classname##_##name), arg_info, flags)
    #define INIT_CLASS_ENTRY(class_container, class_name, functions) 
        INIT_OVERLOADED_CLASS_ENTRY(class_container, class_name, functions, NULL, NULL, NULL)
    ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *orig_class_entry TSRMLS_DC);
    ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *class_entry TSRMLS_DC);
    ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int num_interfaces, ...);
    ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce, char *parent_name TSRMLS_DC);

    Link: http://www.cnblogs.com/farwish/p/5631605.html

  • 相关阅读:
    攻城狮在路上(壹) Hibernate(五)--- 映射一对多关联关系
    攻城狮在路上(壹) Hibernate(四)--- 对象标识符(OID)生成机制
    SQL常用方言列表
    maven 依赖查询
    攻城狮在路上(壹) Hibernate(三)--- 属性访问、命名策略、派生属性、指定包名等
    攻城狮在路上(壹) Hibernate(二)--- 第一个hibernate程序
    《精通Hibernate:Java对象持久化技术详解》目录
    攻城狮在路上(壹) Hibernate(一)--- 软件环境、参考书目等一览表
    <转>Hibernate的优、缺点(局限性)
    攻城狮在路上(零)开篇
  • 原文地址:https://www.cnblogs.com/farwish/p/5631605.html
Copyright © 2020-2023  润新知