From c64f4119a42cee6692b3613356722491e41e6686 Mon Sep 17 00:00:00 2001 From: Vladimir Kolesnikov Date: Wed, 10 Jul 2013 10:06:37 +0300 Subject: [PATCH 1/6] Proof of concept --- ext/config.c | 268 +++++++++++++++++++++++++------------- ext/php_phalcon.h | 10 ++ unit-tests/ConfigTest.php | 10 +- 3 files changed, 193 insertions(+), 95 deletions(-) diff --git a/ext/config.c b/ext/config.c index 6c51772590d..92c7b2bfef2 100755 --- a/ext/config.c +++ b/ext/config.c @@ -65,6 +65,102 @@ * */ +static zend_object_handlers phalcon_config_object_handlers; + +static void phalcon_config_construct_internal(zval *return_value, zval* this_ptr, zval *array_config TSRMLS_DC); + +static zval* phalcon_config_read_dimension_internal(zval *object, zval *offset, int type TSRMLS_DC) +{ + zval* ret; + zend_class_entry *old_scope = EG(scope); + + if (!offset) { + return EG(uninitialized_zval_ptr); + } + + EG(scope) = Z_OBJCE_P(object); + ret = zend_get_std_object_handlers()->read_property(object, offset, type ZLK_NULL_CC TSRMLS_CC); + EG(scope) = old_scope; + + return ret; +} + +static zval* phalcon_config_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) +{ + zend_object *obj = zend_objects_get_address(object TSRMLS_CC); + + if (obj->ce->type != ZEND_INTERNAL_CLASS) { + return zend_get_std_object_handlers()->read_dimension(object, offset, type TSRMLS_CC); + } + + return phalcon_config_read_dimension_internal(object, offset, type TSRMLS_CC); +} + +static void phalcon_config_write_dimension_internal(zval *object, zval *offset, zval *value TSRMLS_DC) +{ + zval* ret; + zend_class_entry *old_scope = EG(scope); + + if (!offset) { + return; + } + + if (Z_TYPE_P(offset) != IS_STRING) { + zend_throw_exception(phalcon_config_exception_ce, "Index key must be string", 0 TSRMLS_CC); + return; + } + + EG(scope) = Z_OBJCE_P(object); + if (Z_TYPE_P(value) == IS_ARRAY) { + zval *tmp, *dummy; + ALLOC_ZVAL(tmp); + object_init_ex(tmp, phalcon_config_ce); + MAKE_STD_ZVAL(dummy); + phalcon_config_construct_internal(dummy, tmp, value TSRMLS_CC); + zval_ptr_dtor(&dummy); + zend_get_std_object_handlers()->write_property(object, offset, value ZLK_NULL_CC TSRMLS_CC); + zval_ptr_dtor(&tmp); + } + else { + zend_get_std_object_handlers()->write_property(object, offset, value ZLK_NULL_CC TSRMLS_CC); + } + + EG(scope) = old_scope; +} + +static void phalcon_config_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) +{ + zend_object *obj = zend_objects_get_address(object TSRMLS_CC); + + if (obj->ce->type != ZEND_INTERNAL_CLASS) { + zend_get_std_object_handlers()->write_dimension(object, offset, value TSRMLS_CC); + } + + phalcon_config_write_dimension_internal(object, offset, value TSRMLS_CC); +} + +static int phalcon_config_has_dimension_internal(zval *object, zval *offset, int check_empty TSRMLS_DC) +{ + int ret; + zend_class_entry *old_scope = EG(scope); + + EG(scope) = Z_OBJCE_P(object); + ret = zend_get_std_object_handlers()->has_property(object, offset, check_empty ZLK_NULL_CC TSRMLS_CC); + EG(scope) = old_scope; + + return ret; +} + +static int phalcon_config_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) +{ + zend_object *obj = zend_objects_get_address(object TSRMLS_CC); + + if (obj->ce->type != ZEND_INTERNAL_CLASS) { + return zend_get_std_object_handlers()->has_dimension(object, offset, check_empty TSRMLS_CC); + } + + return phalcon_config_has_dimension_internal(object, offset, check_empty TSRMLS_CC); +} /** * Phalcon\Config initializer @@ -73,83 +169,97 @@ PHALCON_INIT_CLASS(Phalcon_Config){ PHALCON_REGISTER_CLASS(Phalcon, Config, config, phalcon_config_method_entry, 0); + phalcon_config_object_handlers = *zend_get_std_object_handlers(); + phalcon_config_object_handlers.read_dimension = phalcon_config_read_dimension; + phalcon_config_object_handlers.write_dimension = phalcon_config_write_dimension; + phalcon_config_object_handlers.has_dimension = phalcon_config_has_dimension; + zend_class_implements(phalcon_config_ce TSRMLS_CC, 1, zend_ce_arrayaccess); return SUCCESS; } -/** - * Phalcon\Config constructor - * - * @param array $arrayConfig - */ -PHP_METHOD(Phalcon_Config, __construct){ - - zval *array_config = NULL, *value = NULL, *key = NULL, *config_value = NULL; +void phalcon_config_construct_internal(zval *return_value, zval* this_ptr, zval *array_config TSRMLS_DC) +{ + zval *value = NULL, *key = NULL, *config_value = NULL; HashTable *ah0; HashPosition hp0; zval **hd; PHALCON_MM_GROW(); - phalcon_fetch_params(1, 0, 1, &array_config); - - if (!array_config) { - PHALCON_INIT_VAR(array_config); - } - - /** - * Throw exceptions if bad parameters are passed - */ - if (Z_TYPE_P(array_config) != IS_ARRAY) { - if (Z_TYPE_P(array_config) != IS_NULL) { - PHALCON_THROW_EXCEPTION_STR(phalcon_config_exception_ce, "The configuration must be an Array"); - return; - } else { - RETURN_MM_NULL(); - } - } - phalcon_is_iterable(array_config, &ah0, &hp0, 0, 0); - + while (zend_hash_get_current_data_ex(ah0, (void**) &hd, &hp0) == SUCCESS) { - + PHALCON_GET_HKEY(key, ah0, hp0); PHALCON_GET_HVALUE(value); - - /** + + /** * Phalcon\Config does not support numeric keys as properties */ if (Z_TYPE_P(key) != IS_STRING) { PHALCON_THROW_EXCEPTION_STR(phalcon_config_exception_ce, "Only string keys are allowed as configuration properties"); return; } - if (Z_TYPE_P(value) == IS_ARRAY) { - - /** + if (Z_TYPE_P(value) == IS_ARRAY) { + + /** * Check if sub-arrays contains numeric keys */ if (!phalcon_has_numeric_keys(value)) { + zval *dummy; + MAKE_STD_ZVAL(dummy); + PHALCON_INIT_NVAR(config_value); object_init_ex(config_value, phalcon_config_ce); - phalcon_call_method_p1_noret(config_value, "__construct", value); - + phalcon_config_construct_internal(dummy, config_value, value TSRMLS_CC); phalcon_update_property_zval_zval(this_ptr, key, config_value TSRMLS_CC); + zval_ptr_dtor(&dummy); } else { phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); } } else { - /** + /** * Assign normal keys as properties */ phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); } - + zend_hash_move_forward_ex(ah0, &hp0); } + + PHALCON_MM_RESTORE(); +} + +/** + * Phalcon\Config constructor + * + * @param array $arrayConfig + */ +PHP_METHOD(Phalcon_Config, __construct){ + + zval *array_config = NULL; + + phalcon_fetch_params(0, 0, 1, &array_config); + if (!array_config) { + PHALCON_INIT_VAR(array_config); + } - PHALCON_MM_RESTORE(); + /** + * Throw exceptions if bad parameters are passed + */ + if (Z_TYPE_P(array_config) != IS_ARRAY) { + if (Z_TYPE_P(array_config) != IS_NULL) { + PHALCON_THROW_EXCEPTION_STRW(phalcon_config_exception_ce, "The configuration must be an Array"); + return; + } + + RETURN_NULL(); + } + + phalcon_config_construct_internal(return_value, getThis(), array_config TSRMLS_CC); } /** @@ -167,11 +277,7 @@ PHP_METHOD(Phalcon_Config, offsetExists){ zval *index; phalcon_fetch_params(0, 1, 0, &index); - - if (phalcon_isset_property_zval(this_ptr, index TSRMLS_CC)) { - RETURN_TRUE; - } - RETURN_FALSE; + RETURN_BOOL(phalcon_config_has_dimension_internal(getThis(), index, 0 TSRMLS_CC)); } /** @@ -190,24 +296,21 @@ PHP_METHOD(Phalcon_Config, get){ zval *index, *default_value = NULL, *value; - PHALCON_MM_GROW(); - - phalcon_fetch_params(1, 1, 1, &index, &default_value); + phalcon_fetch_params(0, 1, 1, &index, &default_value); - if (!default_value) { - PHALCON_INIT_VAR(default_value); - } + if (phalcon_config_has_dimension_internal(this_ptr, index, 0 TSRMLS_CC)) { - if (phalcon_isset_property_zval(this_ptr, index TSRMLS_CC)) { - - PHALCON_OBS_VAR(value); - phalcon_read_property_zval(&value, this_ptr, index, PH_NOISY_CC); - if (PHALCON_IS_NOT_EMPTY(value)) { - RETURN_CCTOR(value); + value = phalcon_config_read_dimension_internal(getThis(), index, BP_VAR_R TSRMLS_CC); + if (Z_TYPE_P(value) != IS_NULL) { + RETURN_CCTORW(value); } } - - RETURN_CCTOR(default_value); + + if (default_value) { + RETURN_CCTORW(default_value); + } + + RETURN_NULL(); } /** @@ -222,15 +325,13 @@ PHP_METHOD(Phalcon_Config, get){ */ PHP_METHOD(Phalcon_Config, offsetGet){ - zval *index, *value; + zval *index; + zval* retval; - PHALCON_MM_GROW(); + phalcon_fetch_params(0, 1, 0, &index); - phalcon_fetch_params(1, 1, 0, &index); - - PHALCON_OBS_VAR(value); - phalcon_read_property_zval(&value, this_ptr, index, PH_NOISY_CC); - RETURN_CCTOR(value); + retval = phalcon_config_read_dimension_internal(getThis(), index, BP_VAR_R TSRMLS_CC); + RETURN_ZVAL(retval, 1, 0); } /** @@ -245,28 +346,10 @@ PHP_METHOD(Phalcon_Config, offsetGet){ */ PHP_METHOD(Phalcon_Config, offsetSet){ - zval *index, *value, *array_value = NULL; - - PHALCON_MM_GROW(); + zval *index, *value; - phalcon_fetch_params(1, 2, 0, &index, &value); - - if (Z_TYPE_P(index) != IS_STRING) { - PHALCON_THROW_EXCEPTION_STR(phalcon_config_exception_ce, "Index key must be string"); - return; - } - if (Z_TYPE_P(value) == IS_ARRAY) { - PHALCON_INIT_VAR(array_value); - object_init_ex(array_value, phalcon_config_ce); - phalcon_call_method_p1_noret(array_value, "__construct", value); - - } else { - PHALCON_CPY_WRT(array_value, value); - } - - phalcon_update_property_zval_zval(this_ptr, index, array_value TSRMLS_CC); - - PHALCON_MM_RESTORE(); + phalcon_fetch_params(0, 2, 0, &index, &value); + phalcon_config_write_dimension_internal(getThis(), index, value TSRMLS_CC); } /** @@ -431,15 +514,12 @@ PHP_METHOD(Phalcon_Config, toArray){ */ PHP_METHOD(Phalcon_Config, __set_state){ - zval *data, *config; + zval *data, *tmp; - PHALCON_MM_GROW(); + phalcon_fetch_params(0, 1, 0, &data); - phalcon_fetch_params(1, 1, 0, &data); - - PHALCON_INIT_VAR(config); - object_init_ex(config, phalcon_config_ce); - phalcon_call_method_p1_noret(config, "__construct", data); - - RETURN_CTOR(config); + MAKE_STD_ZVAL(tmp); + object_init_ex(return_value, phalcon_config_ce); + phalcon_config_construct_internal(tmp, return_value, data TSRMLS_CC); + zval_ptr_dtor(&tmp); } diff --git a/ext/php_phalcon.h b/ext/php_phalcon.h index 0d93191edcb..c7d9a369f6a 100755 --- a/ext/php_phalcon.h +++ b/ext/php_phalcon.h @@ -164,3 +164,13 @@ extern zend_module_entry phalcon_module_entry; #define UNREACHABLE() assert(0) #define ASSUME(x) assert(!!(x)); #endif + +#if PHP_VERSION_ID > 50399 +# define ZLK_DC , const struct _zend_literal* key +# define ZLK_CC , key +# define ZLK_NULL_CC , NULL +#else +# define ZLK_DC +# define ZLK_CC +# define ZLK_NULL_CC +#endif diff --git a/unit-tests/ConfigTest.php b/unit-tests/ConfigTest.php index 825b4e97278..117700b9d39 100644 --- a/unit-tests/ConfigTest.php +++ b/unit-tests/ConfigTest.php @@ -231,5 +231,13 @@ public function testIssue732() unset($a['a']); $this->assertTrue(!isset($a['a'])); } -} + public function testGet() + { + $config = new \Phalcon\Config(array('a' => 0, 'b' => null, 'c' => '')); + $this->assertTrue($config->get('a', 1) === 0); + $this->assertTrue($config->get('b', 1) === 1); + $this->assertTrue($config->get('c', 1) === ''); + $this->assertTrue($config->get('d', 1) === 1); + } +} From 9842af243dd06bbb110a966aa270d0ece1174bcd Mon Sep 17 00:00:00 2001 From: Vladimir Kolesnikov Date: Sat, 13 Jul 2013 12:56:06 +0300 Subject: [PATCH 2/6] Rebase --- .gitignore | 1 + ext/kernel/hash.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++ ext/kernel/hash.h | 3 +++ 3 files changed, 68 insertions(+) diff --git a/.gitignore b/.gitignore index 33d7bc7ad03..ea09d257f64 100644 --- a/.gitignore +++ b/.gitignore @@ -474,3 +474,4 @@ unit-tests/annotations/cache/*.php .libs build/t.dSYM/ build/install2 +*~ diff --git a/ext/kernel/hash.c b/ext/kernel/hash.c index 4ba65493eb1..1cd2d54f512 100644 --- a/ext/kernel/hash.c +++ b/ext/kernel/hash.c @@ -179,3 +179,67 @@ int phalcon_has_numeric_keys(const zval *data) return 0; } + +void phalcon_hash_update_or_insert(HashTable *ht, zval *offset, zval *value) +{ + if (!offset || Z_TYPE_P(offset) == IS_NULL) { + zend_hash_next_index_insert(ht, value, sizeof(zval*), NULL); + } + else { + if (Z_TYPE_P(offset) == IS_LONG || Z_TYPE_P(offset) == IS_DOUBLE || Z_TYPE_P(offset) == IS_BOOL) { + zend_hash_index_update(ht, phalcon_get_intval(offset), value, sizeof(zval*), NULL); + } + else { + zval copy; + int use_copy = 0; + + if (Z_TYPE_P(offset) != IS_STRING) { + zend_make_printable_zval(offset, ©, &use_copy); + if (use_copy) { + offset = © + } + } + + zend_hash_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, &value, sizeof(zval*), NULL); + if (use_copy) { + zval_dtor(©); + } + } + } +} + +int phalcon_hash_get(HashTable *ht, zval *offset, zval **value) +{ + switch (Z_TYPE_P(offset)) { + case IS_LONG: + case IS_DOUBLE: + case IS_BOOL: + case IS_RESOURCE: + return (zend_hash_index_find(ht, (Z_TYPE_P(offset) == IS_DOUBLE) ? ((long int)Z_DVAL_P(offset)) : Z_LVAL_P(offset), (void**)value) == SUCCESS); + + case IS_STRING: + return (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)value) == SUCCESS); + + default: + zend_error(E_WARNING, "Illegal offset type"); + return 0; + } +} + +int phalcon_hash_unset(HashTable *ht, zval *offset) +{ + switch (Z_TYPE_P(offset)) { + case IS_LONG: + case IS_DOUBLE: + case IS_BOOL: + case IS_RESOURCE: + return (zend_hash_index_del(ht, (Z_TYPE_P(offset) == IS_DOUBLE) ? ((long int)Z_DVAL_P(offset)) : Z_LVAL_P(offset)) == SUCCESS); + + case IS_STRING: + return (zend_symtable_del(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == SUCCESS); + + default: + zend_error(E_WARNING, "Illegal offset type"); + return 0; + } +} diff --git a/ext/kernel/hash.h b/ext/kernel/hash.h index dbf82e38888..a7d6989f1c7 100644 --- a/ext/kernel/hash.h +++ b/ext/kernel/hash.h @@ -24,3 +24,6 @@ int phalcon_hash_quick_find(const HashTable *ht, const char *arKey, uint nKeyLen void phalcon_get_current_key(zval **key, const HashTable *hash_table, HashPosition *hash_position TSRMLS_DC); zval phalcon_get_current_key_w(const HashTable *hash_table, HashPosition *hash_position); int phalcon_has_numeric_keys(const zval *data); +void phalcon_hash_update_or_insert(HashTable *ht, zval *offset, zval *value); +int phalcon_hash_get(HashTable *ht, zval *offset, zval **value); +int phalcon_hash_unset(HashTable *ht, zval *offset); From bc09adb2cb20bdb0c0ab0acdd54b5dc669809d35 Mon Sep 17 00:00:00 2001 From: Vladimir Kolesnikov Date: Sat, 13 Jul 2013 18:38:59 +0300 Subject: [PATCH 3/6] Hash funcrions tailored for object handlers --- ext/kernel/hash.c | 125 +++++++++++++++++++++++++++++++++++----------- ext/kernel/hash.h | 2 +- 2 files changed, 96 insertions(+), 31 deletions(-) diff --git a/ext/kernel/hash.c b/ext/kernel/hash.c index 1cd2d54f512..421deb576a0 100644 --- a/ext/kernel/hash.c +++ b/ext/kernel/hash.c @@ -180,49 +180,114 @@ int phalcon_has_numeric_keys(const zval *data) return 0; } -void phalcon_hash_update_or_insert(HashTable *ht, zval *offset, zval *value) +void phalcon_hash_update_or_insert(HashTable *ht, zval *key, zval *value) { - if (!offset || Z_TYPE_P(offset) == IS_NULL) { - zend_hash_next_index_insert(ht, value, sizeof(zval*), NULL); + if (!key || Z_TYPE_P(key) == IS_NULL) { + zend_hash_next_index_insert(ht, (void**)&value, sizeof(zval*), NULL); + return; } - else { - if (Z_TYPE_P(offset) == IS_LONG || Z_TYPE_P(offset) == IS_DOUBLE || Z_TYPE_P(offset) == IS_BOOL) { - zend_hash_index_update(ht, phalcon_get_intval(offset), value, sizeof(zval*), NULL); - } - else { - zval copy; - int use_copy = 0; - - if (Z_TYPE_P(offset) != IS_STRING) { - zend_make_printable_zval(offset, ©, &use_copy); - if (use_copy) { - offset = © - } - } - zend_hash_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, &value, sizeof(zval*), NULL); - if (use_copy) { - zval_dtor(©); - } - } + switch (Z_TYPE_P(key)) { + case IS_STRING: + zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key)+1, (void**)&value, sizeof(zval*), NULL); + return; + + case IS_RESOURCE: + case IS_DOUBLE: + case IS_BOOL: + case IS_LONG: + zend_hash_index_update(ht, ((Z_TYPE_P(key) == IS_DOUBLE) ? (ulong)Z_DVAL_P(key) : Z_LVAL_P(key)), (void*)&value, sizeof(zval*), NULL); + return; + + default: + zend_error(E_WARNING, "Illegal offset type"); + return; } } -int phalcon_hash_get(HashTable *ht, zval *offset, zval **value) +/** + * @brief Gets an entry from @a ht identified by @a key and puts it to @a *value + * @param[in] ht Hash table + * @param[in] offset + * @param[out] value + * @return + * @retval @c SUCCESS + * @retval @c FAILURE + * @throw @c E_WARNING when @a key is of not supported type + * @note @a *value is not modified on failure + * @note Reference count of the retrieved item is not modified + */ +zval** phalcon_hash_get(HashTable *ht, const zval *key, int type) { - switch (Z_TYPE_P(offset)) { + zval **ret = NULL; + + switch (Z_TYPE_P(key)) { + case IS_RESOURCE: + zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(key), Z_LVAL_P(key)); + /* no break */ case IS_LONG: case IS_DOUBLE: - case IS_BOOL: - case IS_RESOURCE: - return (zend_hash_index_find(ht, (Z_TYPE_P(offset) == IS_DOUBLE) ? ((long int)Z_DVAL_P(offset)) : Z_LVAL_P(offset), (void**)value) == SUCCESS); + case IS_BOOL: { + ulong index = (Z_TYPE_P(key) == IS_DOUBLE) ? ((long int)Z_DVAL_P(key)) : Z_LVAL_P(key); + if (FAILURE == zend_hash_index_find(ht, index, (void**)&ret)) { + switch (type) { + case BP_VAR_R: + zend_error(E_NOTICE, "Undefined offset: %ld", index); + /* no break */ + case BP_VAR_UNSET: + case BP_VAR_IS: { + TSRMLS_FETCH(); + ret = &EG(uninitialized_zval_ptr); + break; + } + + case BP_VAR_RW: + zend_error(E_NOTICE, "Undefined offset: %ld", index); + /* no break */ + case BP_VAR_W: { + zval *value; + ALLOC_INIT_ZVAL(value); + zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL); + break; + } + } + } + + return ret; + } case IS_STRING: - return (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)value) == SUCCESS); + if (FAILURE == zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key)+1, (void**)&ret)) { + switch (type) { + case BP_VAR_R: + zend_error(E_NOTICE, "Undefined offset: %s", Z_STRVAL_P(key)); + /* no break */ + case BP_VAR_UNSET: + case BP_VAR_IS: { + TSRMLS_FETCH(); + ret = &EG(uninitialized_zval_ptr); + break; + } + + case BP_VAR_RW: + zend_error(E_NOTICE, "Undefined offset: %s", Z_STRVAL_P(key)); + /* no break */ + case BP_VAR_W: { + zval *value; + ALLOC_INIT_ZVAL(value); + zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key)+1, (void**)&value, sizeof(void*), NULL); + break; + } + } + } - default: + return ret; + + default: { + TSRMLS_FETCH(); zend_error(E_WARNING, "Illegal offset type"); - return 0; + return (type == BP_VAR_W || type == BP_VAR_RW) ? &EG(error_zval_ptr) : &EG(uninitialized_zval_ptr); + } } } diff --git a/ext/kernel/hash.h b/ext/kernel/hash.h index a7d6989f1c7..0b963f1d912 100644 --- a/ext/kernel/hash.h +++ b/ext/kernel/hash.h @@ -25,5 +25,5 @@ void phalcon_get_current_key(zval **key, const HashTable *hash_table, HashPositi zval phalcon_get_current_key_w(const HashTable *hash_table, HashPosition *hash_position); int phalcon_has_numeric_keys(const zval *data); void phalcon_hash_update_or_insert(HashTable *ht, zval *offset, zval *value); -int phalcon_hash_get(HashTable *ht, zval *offset, zval **value); +zval** phalcon_hash_get(HashTable *ht, zval *key, int type); int phalcon_hash_unset(HashTable *ht, zval *offset); From 3dc32f50edb57cf16328292fad1c3c56efbe787a Mon Sep 17 00:00:00 2001 From: Vladimir Kolesnikov Date: Sat, 13 Jul 2013 18:39:49 +0300 Subject: [PATCH 4/6] Phalcon\Config implementation using object handlers --- ext/config.c | 448 +++++++++++++++++++++++++++++++------------------- ext/pconfig.h | 15 +- 2 files changed, 292 insertions(+), 171 deletions(-) diff --git a/ext/config.c b/ext/config.c index 92c7b2bfef2..aecd2e82d6f 100755 --- a/ext/config.c +++ b/ext/config.c @@ -67,99 +67,235 @@ static zend_object_handlers phalcon_config_object_handlers; -static void phalcon_config_construct_internal(zval *return_value, zval* this_ptr, zval *array_config TSRMLS_DC); +typedef struct _phalcon_config_object { + zend_object obj; /**< Zend object data */ + HashTable* props; /**< Properties */ +} phalcon_config_object; -static zval* phalcon_config_read_dimension_internal(zval *object, zval *offset, int type TSRMLS_DC) +/** + * @brief Fetches @c phalcon_config_object + * @see phalcon_config_object + * @param zobj @c \Phalcon\Config instance + * @return phalcon_config_object associated with @a zobj + * @pre Z_TYPE_P(zobj) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zobj), phalcon_config_ce TSRMLS_CC) + */ +static inline phalcon_config_object* fetchPhalconConfigObject(zval* zobj TSRMLS_DC) { - zval* ret; - zend_class_entry *old_scope = EG(scope); +#ifndef PHALCON_RELEASE + assert(Z_TYPE_P(zobj) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zobj), phalcon_config_ce TSRMLS_CC)); +#endif + + return (phalcon_config_object*)zend_objects_get_address(zobj TSRMLS_CC); +} + +static void phalcon_config_construct_internal(zval *this_ptr, zval *array_config TSRMLS_DC); + +static int phalcon_config_count_elements(zval *object, long int *count TSRMLS_DC) +{ + phalcon_config_object* obj = fetchPhalconConfigObject(object TSRMLS_CC); + *count = zend_hash_num_elements(obj->props); + return SUCCESS; +} - if (!offset) { +static zval* phalcon_config_read_internal(phalcon_config_object *object, zval *key, int type TSRMLS_DC) +{ + zval **retval; + if (UNEXPECTED(!key)) { return EG(uninitialized_zval_ptr); } - EG(scope) = Z_OBJCE_P(object); - ret = zend_get_std_object_handlers()->read_property(object, offset, type ZLK_NULL_CC TSRMLS_CC); - EG(scope) = old_scope; - - return ret; + retval = phalcon_hash_get(object->props, key, type); + return retval ? *retval : NULL; } -static zval* phalcon_config_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) +static zval* phalcon_config_read_property(zval *object, zval *offset, int type ZLK_DC TSRMLS_DC) { - zend_object *obj = zend_objects_get_address(object TSRMLS_CC); + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); - if (obj->ce->type != ZEND_INTERNAL_CLASS) { - return zend_get_std_object_handlers()->read_dimension(object, offset, type TSRMLS_CC); + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + return zend_get_std_object_handlers()->read_property(object, offset, type ZLK_CC TSRMLS_CC); } - return phalcon_config_read_dimension_internal(object, offset, type TSRMLS_CC); + return phalcon_config_read_internal(obj, offset, type TSRMLS_CC); } -static void phalcon_config_write_dimension_internal(zval *object, zval *offset, zval *value TSRMLS_DC) +static zval* phalcon_config_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) { - zval* ret; - zend_class_entry *old_scope = EG(scope); + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); - if (!offset) { - return; + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + return zend_get_std_object_handlers()->read_dimension(object, offset, type TSRMLS_CC); } - if (Z_TYPE_P(offset) != IS_STRING) { - zend_throw_exception(phalcon_config_exception_ce, "Index key must be string", 0 TSRMLS_CC); - return; - } + return phalcon_config_read_internal(obj, offset, type TSRMLS_CC); +} - EG(scope) = Z_OBJCE_P(object); +static void phalcon_config_write_internal(phalcon_config_object *object, zval *offset, zval *value TSRMLS_DC) +{ if (Z_TYPE_P(value) == IS_ARRAY) { - zval *tmp, *dummy; - ALLOC_ZVAL(tmp); - object_init_ex(tmp, phalcon_config_ce); - MAKE_STD_ZVAL(dummy); - phalcon_config_construct_internal(dummy, tmp, value TSRMLS_CC); - zval_ptr_dtor(&dummy); - zend_get_std_object_handlers()->write_property(object, offset, value ZLK_NULL_CC TSRMLS_CC); - zval_ptr_dtor(&tmp); + zval *instance; + ALLOC_INIT_ZVAL(instance); + object_init_ex(instance, phalcon_config_ce); + phalcon_config_construct_internal(instance, value TSRMLS_CC); + phalcon_hash_update_or_insert(object->props, offset, instance); } else { - zend_get_std_object_handlers()->write_property(object, offset, value ZLK_NULL_CC TSRMLS_CC); + Z_ADDREF_P(value); + phalcon_hash_update_or_insert(object->props, offset, value); } +} - EG(scope) = old_scope; +static void phalcon_config_write_property(zval *object, zval *offset, zval *value ZLK_DC TSRMLS_DC) +{ + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); + + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + zend_get_std_object_handlers()->write_property(object, offset, value ZLK_CC TSRMLS_CC); + } + + phalcon_config_write_internal(obj, offset, value TSRMLS_CC); } static void phalcon_config_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) { - zend_object *obj = zend_objects_get_address(object TSRMLS_CC); + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); - if (obj->ce->type != ZEND_INTERNAL_CLASS) { + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { zend_get_std_object_handlers()->write_dimension(object, offset, value TSRMLS_CC); } - phalcon_config_write_dimension_internal(object, offset, value TSRMLS_CC); + phalcon_config_write_internal(obj, offset, value TSRMLS_CC); +} + +static int phalcon_config_has_internal(phalcon_config_object *object, zval *key, int check_empty TSRMLS_DC) +{ + zval **tmp = phalcon_hash_get(object->props, key, BP_VAR_NA); + + if (!tmp) { + return 0; + } + + if (0 == check_empty) { + return Z_TYPE_PP(tmp) != IS_NULL; + } + + if (1 == check_empty) { + return zend_is_true(*tmp); + } + + return 1; } -static int phalcon_config_has_dimension_internal(zval *object, zval *offset, int check_empty TSRMLS_DC) +static int phalcon_config_has_property(zval *object, zval *offset, int has_set_exists ZLK_DC TSRMLS_DC) { - int ret; - zend_class_entry *old_scope = EG(scope); + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); - EG(scope) = Z_OBJCE_P(object); - ret = zend_get_std_object_handlers()->has_property(object, offset, check_empty ZLK_NULL_CC TSRMLS_CC); - EG(scope) = old_scope; + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + return zend_get_std_object_handlers()->has_property(object, offset, has_set_exists ZLK_CC TSRMLS_CC); + } - return ret; + return phalcon_config_has_internal(obj, offset, 2 TSRMLS_CC); } static int phalcon_config_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) { - zend_object *obj = zend_objects_get_address(object TSRMLS_CC); + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); - if (obj->ce->type != ZEND_INTERNAL_CLASS) { + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { return zend_get_std_object_handlers()->has_dimension(object, offset, check_empty TSRMLS_CC); } - return phalcon_config_has_dimension_internal(object, offset, check_empty TSRMLS_CC); + return phalcon_config_has_internal(obj, offset, check_empty TSRMLS_CC); +} + +static void phalcon_config_unset_internal(phalcon_config_object *obj, zval *key TSRMLS_DC) +{ + phalcon_hash_unset(obj->props, key); +} + +static void phalcon_config_unset_property(zval *object, zval *member ZLK_DC TSRMLS_DC) +{ + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); + + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + zend_get_std_object_handlers()->unset_property(object, member ZLK_CC TSRMLS_CC); + } + + phalcon_config_unset_internal(obj, member TSRMLS_CC); +} + +static void phalcon_config_unset_dimension(zval *object, zval *offset TSRMLS_DC) +{ + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); + + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + zend_get_std_object_handlers()->unset_dimension(object, offset TSRMLS_CC); + } + + phalcon_config_unset_internal(obj, offset TSRMLS_CC); +} + + +static HashTable* phalcon_config_get_properties(zval* object TSRMLS_DC) +{ + phalcon_config_object* obj = fetchPhalconConfigObject(object TSRMLS_CC); + HashTable* props = zend_std_get_properties(object TSRMLS_CC); + zval *tmp; + + zend_hash_copy(props, obj->props, (copy_ctor_func_t)zval_add_ref, (void*)&tmp, sizeof(zval*)); + return props; +} + +static int phalcon_config_compare_objects(zval *object1, zval *object2 TSRMLS_DC) +{ + phalcon_config_object *zobj1, *zobj2; + zval result; + + zobj1 = fetchPhalconConfigObject(object1 TSRMLS_CC); + zobj2 = fetchPhalconConfigObject(object2 TSRMLS_CC); + + if (zobj1->obj.ce != zobj2->obj.ce) { + return 1; + } + + if (zobj1->props == zobj2->props) { + return 0; + } + + zend_compare_symbol_tables(&result, zobj1->props, zobj2->props TSRMLS_CC); + assert(Z_TYPE_P(&result) == IS_LONG); + return Z_LVAL_P(&result); +} + +static void phalcon_config_object_dtor(void* v TSRMLS_DC) +{ + phalcon_config_object* obj = v; + + if (obj->props) { + zend_hash_destroy(obj->props); + FREE_HASHTABLE(obj->props); + } + + zend_object_std_dtor(&(obj->obj) TSRMLS_CC); + efree(obj); +} + +static zend_object_value phalcon_config_object_ctor(zend_class_entry* ce TSRMLS_DC) +{ + phalcon_config_object* obj = ecalloc(1, sizeof(phalcon_config_object)); + zend_object_value retval; + + zend_object_std_init(&(obj->obj), ce TSRMLS_CC); + retval.handle = zend_objects_store_put( + obj, + (zend_objects_store_dtor_t)zend_objects_destroy_object, + phalcon_config_object_dtor, + NULL TSRMLS_CC + ); + + retval.handlers = &phalcon_config_object_handlers; + + return retval; } /** @@ -169,67 +305,70 @@ PHALCON_INIT_CLASS(Phalcon_Config){ PHALCON_REGISTER_CLASS(Phalcon, Config, config, phalcon_config_method_entry, 0); + phalcon_config_ce->create_object = phalcon_config_object_ctor; + phalcon_config_object_handlers = *zend_get_std_object_handlers(); + phalcon_config_object_handlers.count_elements = phalcon_config_count_elements; + phalcon_config_object_handlers.read_property = phalcon_config_read_property; + phalcon_config_object_handlers.write_property = phalcon_config_write_property; + phalcon_config_object_handlers.unset_property = phalcon_config_unset_property; + phalcon_config_object_handlers.has_property = phalcon_config_has_property; phalcon_config_object_handlers.read_dimension = phalcon_config_read_dimension; phalcon_config_object_handlers.write_dimension = phalcon_config_write_dimension; + phalcon_config_object_handlers.unset_dimension = phalcon_config_unset_dimension; phalcon_config_object_handlers.has_dimension = phalcon_config_has_dimension; + phalcon_config_object_handlers.get_properties = phalcon_config_get_properties; + phalcon_config_object_handlers.compare_objects = phalcon_config_compare_objects; - zend_class_implements(phalcon_config_ce TSRMLS_CC, 1, zend_ce_arrayaccess); + zend_class_implements(phalcon_config_ce TSRMLS_CC, 2, zend_ce_arrayaccess, spl_ce_Countable); return SUCCESS; } -void phalcon_config_construct_internal(zval *return_value, zval* this_ptr, zval *array_config TSRMLS_DC) +void phalcon_config_construct_internal(zval* this_ptr, zval *array_config TSRMLS_DC) { - zval *value = NULL, *key = NULL, *config_value = NULL; HashTable *ah0; HashPosition hp0; zval **hd; + phalcon_config_object* obj; - PHALCON_MM_GROW(); + if (!array_config || Z_TYPE_P(array_config) == IS_NULL) { + obj = fetchPhalconConfigObject(getThis() TSRMLS_CC); + ALLOC_HASHTABLE(obj->props); + zend_hash_init(obj->props, 0, NULL, ZVAL_PTR_DTOR, 0); + return; + } phalcon_is_iterable(array_config, &ah0, &hp0, 0, 0); - while (zend_hash_get_current_data_ex(ah0, (void**) &hd, &hp0) == SUCCESS) { + obj = fetchPhalconConfigObject(getThis() TSRMLS_CC); + ALLOC_HASHTABLE(obj->props); + zend_hash_init(obj->props, zend_hash_num_elements(Z_ARRVAL_P(array_config)), NULL, ZVAL_PTR_DTOR, 0); - PHALCON_GET_HKEY(key, ah0, hp0); - PHALCON_GET_HVALUE(value); - - /** - * Phalcon\Config does not support numeric keys as properties - */ - if (Z_TYPE_P(key) != IS_STRING) { - PHALCON_THROW_EXCEPTION_STR(phalcon_config_exception_ce, "Only string keys are allowed as configuration properties"); - return; - } - if (Z_TYPE_P(value) == IS_ARRAY) { + while (zend_hash_get_current_data_ex(ah0, (void**) &hd, &hp0) == SUCCESS) { - /** - * Check if sub-arrays contains numeric keys - */ - if (!phalcon_has_numeric_keys(value)) { - zval *dummy; - MAKE_STD_ZVAL(dummy); - - PHALCON_INIT_NVAR(config_value); - object_init_ex(config_value, phalcon_config_ce); - phalcon_config_construct_internal(dummy, config_value, value TSRMLS_CC); - phalcon_update_property_zval_zval(this_ptr, key, config_value TSRMLS_CC); - zval_ptr_dtor(&dummy); - } else { - phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); - } - } else { - /** - * Assign normal keys as properties - */ - phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); - } + zval key = phalcon_get_current_key_w(ah0, &hp0); + phalcon_config_write_internal(obj, &key, *hd TSRMLS_CC); zend_hash_move_forward_ex(ah0, &hp0); } +} - PHALCON_MM_RESTORE(); +static void phalcon_config_toarray_internal(zval *return_value, zval *this_ptr TSRMLS_DC) +{ + phalcon_config_object *obj = fetchPhalconConfigObject(this_ptr TSRMLS_CC); + + if (likely(obj->obj.ce == phalcon_config_ce)) { + zval *tmp; + array_init_size(return_value, zend_hash_num_elements(obj->props)); + zend_hash_copy(Z_ARRVAL_P(return_value), obj->props, (copy_ctor_func_t)zval_add_ref, (void*)&tmp, sizeof(zval*)); + } + else if (phalcon_method_exists_ex(this_ptr, SS("toarray") TSRMLS_CC) == SUCCESS) { + phalcon_call_method(return_value, this_ptr, "toarray"); + } + else { + phalcon_call_func(return_value, "get_object_vars"); + } } /** @@ -243,23 +382,15 @@ PHP_METHOD(Phalcon_Config, __construct){ phalcon_fetch_params(0, 0, 1, &array_config); - if (!array_config) { - PHALCON_INIT_VAR(array_config); - } - /** * Throw exceptions if bad parameters are passed */ - if (Z_TYPE_P(array_config) != IS_ARRAY) { - if (Z_TYPE_P(array_config) != IS_NULL) { - PHALCON_THROW_EXCEPTION_STRW(phalcon_config_exception_ce, "The configuration must be an Array"); - return; - } - - RETURN_NULL(); + if (array_config && Z_TYPE_P(array_config) != IS_ARRAY && Z_TYPE_P(array_config) != IS_NULL) { + PHALCON_THROW_EXCEPTION_STRW(phalcon_config_exception_ce, "The configuration must be an Array"); + return; } - - phalcon_config_construct_internal(return_value, getThis(), array_config TSRMLS_CC); + + phalcon_config_construct_internal(getThis(), array_config TSRMLS_CC); } /** @@ -277,7 +408,7 @@ PHP_METHOD(Phalcon_Config, offsetExists){ zval *index; phalcon_fetch_params(0, 1, 0, &index); - RETURN_BOOL(phalcon_config_has_dimension_internal(getThis(), index, 0 TSRMLS_CC)); + RETURN_BOOL(phalcon_config_has_internal(fetchPhalconConfigObject(getThis() TSRMLS_CC), index, 0 TSRMLS_CC)); } /** @@ -297,20 +428,17 @@ PHP_METHOD(Phalcon_Config, get){ zval *index, *default_value = NULL, *value; phalcon_fetch_params(0, 1, 1, &index, &default_value); - - if (phalcon_config_has_dimension_internal(this_ptr, index, 0 TSRMLS_CC)) { - - value = phalcon_config_read_dimension_internal(getThis(), index, BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(value) != IS_NULL) { - RETURN_CCTORW(value); + + value = phalcon_config_read_internal(fetchPhalconConfigObject(getThis() TSRMLS_CC), index, BP_VAR_NA TSRMLS_CC); + if (!value || Z_TYPE_P(value) == IS_NULL) { + if (default_value) { + RETURN_ZVAL(default_value, 1, 0); } - } - if (default_value) { - RETURN_CCTORW(default_value); + RETURN_NULL(); } - RETURN_NULL(); + RETURN_ZVAL(value, 1, 0); } /** @@ -330,7 +458,7 @@ PHP_METHOD(Phalcon_Config, offsetGet){ phalcon_fetch_params(0, 1, 0, &index); - retval = phalcon_config_read_dimension_internal(getThis(), index, BP_VAR_R TSRMLS_CC); + retval = phalcon_config_read_internal(fetchPhalconConfigObject(getThis() TSRMLS_CC), index, BP_VAR_R TSRMLS_CC); RETURN_ZVAL(retval, 1, 0); } @@ -349,7 +477,7 @@ PHP_METHOD(Phalcon_Config, offsetSet){ zval *index, *value; phalcon_fetch_params(0, 2, 0, &index, &value); - phalcon_config_write_dimension_internal(getThis(), index, value TSRMLS_CC); + phalcon_config_write_internal(fetchPhalconConfigObject(getThis() TSRMLS_CC), index, value TSRMLS_CC); } /** @@ -366,13 +494,7 @@ PHP_METHOD(Phalcon_Config, offsetUnset){ zval *index; phalcon_fetch_params(0, 1, 0, &index); -#if PHP_VERSION_ID < 50400 - Z_OBJ_HANDLER_P(getThis(), unset_property)(getThis(), index TSRMLS_CC); -#else - Z_OBJ_HANDLER_P(getThis(), unset_property)(getThis(), index, 0 TSRMLS_CC); -#endif - - RETURN_TRUE; + phalcon_config_unset_internal(fetchPhalconConfigObject(getThis() TSRMLS_CC), index TSRMLS_CC); } /** @@ -387,78 +509,61 @@ PHP_METHOD(Phalcon_Config, offsetUnset){ */ PHP_METHOD(Phalcon_Config, merge){ - zval *config, *array_config, *value = NULL, *key = NULL, *active_value = NULL; - zval *other_array = NULL; + zval *config, *array_config, *value = NULL, key, *active_value = NULL; HashTable *ah0; HashPosition hp0; zval **hd; + phalcon_config_object *obj; - PHALCON_MM_GROW(); - - phalcon_fetch_params(1, 1, 0, &config); + phalcon_fetch_params(0, 1, 0, &config); if (Z_TYPE_P(config) != IS_OBJECT) { - PHALCON_THROW_EXCEPTION_STR(phalcon_config_exception_ce, "Configuration must be an Object"); + PHALCON_THROW_EXCEPTION_STRW(phalcon_config_exception_ce, "Configuration must be an Object"); return; } - - PHALCON_INIT_VAR(array_config); - phalcon_call_func_p1(array_config, "get_object_vars", config); + + PHALCON_MM_GROW(); + ALLOC_INIT_ZVAL(array_config); + phalcon_config_toarray_internal(array_config, config TSRMLS_CC); phalcon_is_iterable(array_config, &ah0, &hp0, 0, 0); + obj = fetchPhalconConfigObject(getThis() TSRMLS_CC); + while (zend_hash_get_current_data_ex(ah0, (void**) &hd, &hp0) == SUCCESS) { - PHALCON_GET_HKEY(key, ah0, hp0); + key = phalcon_get_current_key_w(ah0, &hp0); PHALCON_GET_HVALUE(value); - if (phalcon_isset_property_zval(this_ptr, key TSRMLS_CC)) { - - /** - * The key is already defined in the object, we have to merge it - */ - PHALCON_OBS_NVAR(active_value); - phalcon_read_property_zval(&active_value, this_ptr, key, PH_NOISY_CC); + active_value = phalcon_config_read_internal(obj, &key, BP_VAR_NA TSRMLS_CC); + /** + * The key is already defined in the object, we have to merge it + */ + if (active_value) { if (Z_TYPE_P(value) == IS_OBJECT && Z_TYPE_P(active_value) == IS_OBJECT) { if (phalcon_method_exists_ex(active_value, SS("merge") TSRMLS_CC) == SUCCESS) { /* Path AAA in the test */ phalcon_call_method_p1_noret(active_value, "merge", value); } else { /* Path AAB in the test */ - phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); + phalcon_config_write_internal(obj, &key, value TSRMLS_CC); } } - else if (Z_TYPE_P(value) == IS_OBJECT && Z_TYPE_P(active_value) == IS_ARRAY) { /* Path AB in the test */ - PHALCON_INIT_NVAR(other_array); - phalcon_call_func_p1(other_array, "get_object_vars", value); - phalcon_array_merge_recursive_n(&active_value, other_array); - phalcon_update_property_zval_zval(this_ptr, key, active_value TSRMLS_CC); - } - else if (Z_TYPE_P(value) == IS_ARRAY && Z_TYPE_P(active_value) == IS_OBJECT) { /* Path AC in the test */ - PHALCON_INIT_NVAR(other_array); - phalcon_call_func_p1(other_array, "get_object_vars", active_value); - phalcon_array_merge_recursive_n(&other_array, value); - phalcon_update_property_zval_zval(this_ptr, key, other_array TSRMLS_CC); - } - else if (Z_TYPE_P(value) == IS_ARRAY && Z_TYPE_P(active_value) == IS_ARRAY) { /* Path AD in the test */ - phalcon_array_merge_recursive_n(&active_value, value); - phalcon_update_property_zval_zval(this_ptr, key, active_value TSRMLS_CC); - } else { /* Path AE in the test */ - phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); + phalcon_config_write_internal(obj, &key, value TSRMLS_CC); } } else { /* Path B in the test */ /** * The key is not defined in the object, add it */ - phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); + phalcon_config_write_internal(obj, &key, value TSRMLS_CC); } zend_hash_move_forward_ex(ah0, &hp0); } - + zval_ptr_dtor(&array_config); PHALCON_MM_RESTORE(); } @@ -473,17 +578,18 @@ PHP_METHOD(Phalcon_Config, merge){ */ PHP_METHOD(Phalcon_Config, toArray){ - zval *array_config, *value = NULL, *key = NULL, *array_value = NULL; + zval *value = NULL, *key = NULL, *array_value = NULL, *tmp; HashTable *ah0; HashPosition hp0; zval **hd; + phalcon_config_object *obj = fetchPhalconConfigObject(getThis() TSRMLS_CC); PHALCON_MM_GROW(); - PHALCON_INIT_VAR(array_config); - phalcon_call_func_p1(array_config, "get_object_vars", this_ptr); - - phalcon_is_iterable(array_config, &ah0, &hp0, 1, 0); + array_init_size(return_value, zend_hash_num_elements(obj->props)); + zend_hash_copy(Z_ARRVAL_P(return_value), obj->props, (copy_ctor_func_t)zval_add_ref, (void*)&tmp, sizeof(zval*)); + + phalcon_is_iterable(return_value, &ah0, &hp0, 0, 0); while (zend_hash_get_current_data_ex(ah0, (void**) &hd, &hp0) == SUCCESS) { @@ -494,16 +600,22 @@ PHP_METHOD(Phalcon_Config, toArray){ if (phalcon_method_exists_ex(value, SS("toarray") TSRMLS_CC) == SUCCESS) { PHALCON_INIT_NVAR(array_value); phalcon_call_method(array_value, value, "toarray"); - phalcon_array_update_zval(&array_config, key, &array_value, PH_COPY | PH_SEPARATE); + phalcon_array_update_zval(&return_value, key, &array_value, PH_COPY | PH_SEPARATE); } } zend_hash_move_forward_ex(ah0, &hp0); } - zend_hash_destroy(ah0); - efree(ah0); - RETURN_CCTOR(array_config); + RETURN_MM(); +} + +PHP_METHOD(Phalcon_Config, count) +{ + long int cnt; + + phalcon_config_count_elements(getThis(), &cnt TSRMLS_CC); + RETURN_LONG(cnt); } /** @@ -514,12 +626,10 @@ PHP_METHOD(Phalcon_Config, toArray){ */ PHP_METHOD(Phalcon_Config, __set_state){ - zval *data, *tmp; + zval *data; phalcon_fetch_params(0, 1, 0, &data); - MAKE_STD_ZVAL(tmp); object_init_ex(return_value, phalcon_config_ce); - phalcon_config_construct_internal(tmp, return_value, data TSRMLS_CC); - zval_ptr_dtor(&tmp); + phalcon_config_construct_internal(return_value, data TSRMLS_CC); } diff --git a/ext/pconfig.h b/ext/pconfig.h index c2365b3c5e7..d2be9569896 100644 --- a/ext/pconfig.h +++ b/ext/pconfig.h @@ -29,6 +29,7 @@ PHP_METHOD(Phalcon_Config, offsetSet); PHP_METHOD(Phalcon_Config, offsetUnset); PHP_METHOD(Phalcon_Config, merge); PHP_METHOD(Phalcon_Config, toArray); +PHP_METHOD(Phalcon_Config, count); PHP_METHOD(Phalcon_Config, __set_state); ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_config___construct, 0, 0, 0) @@ -61,6 +62,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_config_merge, 0, 0, 1) ZEND_ARG_INFO(0, config) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_config_toarray, 0, 0, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_config_count, 0, 0, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_config___set_state, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO() @@ -73,8 +80,12 @@ PHALCON_INIT_FUNCS(phalcon_config_method_entry){ PHP_ME(Phalcon_Config, offsetSet, arginfo_phalcon_config_offsetset, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Config, offsetUnset, arginfo_phalcon_config_offsetunset, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Config, merge, arginfo_phalcon_config_merge, ZEND_ACC_PUBLIC) - PHP_ME(Phalcon_Config, toArray, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Phalcon_Config, __set_state, arginfo_phalcon_config___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(Phalcon_Config, toArray, arginfo_phalcon_config_toarray, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Config, count, arginfo_phalcon_config_count, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Config, __set_state, arginfo_phalcon_config___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_MALIAS(Phalcon_Config, __get, offsetGet, arginfo_phalcon_config_offsetget, ZEND_ACC_PUBLIC) + PHP_MALIAS(Phalcon_Config, __set, offsetSet, arginfo_phalcon_config_offsetset, ZEND_ACC_PUBLIC) + PHP_MALIAS(Phalcon_Config, __isset, offsetExists, arginfo_phalcon_config_offsetexists, ZEND_ACC_PUBLIC) PHP_FE_END }; From 09ff37c604575d15a2f56326002d82148aa06bff Mon Sep 17 00:00:00 2001 From: Vladimir Kolesnikov Date: Sat, 13 Jul 2013 18:39:49 +0300 Subject: [PATCH 5/6] Documented all changes in kernel/hash.c --- ext/config.c | 448 +++++++++++++++++++++++++++++++------------------- ext/pconfig.h | 15 +- 2 files changed, 292 insertions(+), 171 deletions(-) diff --git a/ext/config.c b/ext/config.c index 92c7b2bfef2..aecd2e82d6f 100755 --- a/ext/config.c +++ b/ext/config.c @@ -67,99 +67,235 @@ static zend_object_handlers phalcon_config_object_handlers; -static void phalcon_config_construct_internal(zval *return_value, zval* this_ptr, zval *array_config TSRMLS_DC); +typedef struct _phalcon_config_object { + zend_object obj; /**< Zend object data */ + HashTable* props; /**< Properties */ +} phalcon_config_object; -static zval* phalcon_config_read_dimension_internal(zval *object, zval *offset, int type TSRMLS_DC) +/** + * @brief Fetches @c phalcon_config_object + * @see phalcon_config_object + * @param zobj @c \Phalcon\Config instance + * @return phalcon_config_object associated with @a zobj + * @pre Z_TYPE_P(zobj) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zobj), phalcon_config_ce TSRMLS_CC) + */ +static inline phalcon_config_object* fetchPhalconConfigObject(zval* zobj TSRMLS_DC) { - zval* ret; - zend_class_entry *old_scope = EG(scope); +#ifndef PHALCON_RELEASE + assert(Z_TYPE_P(zobj) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zobj), phalcon_config_ce TSRMLS_CC)); +#endif + + return (phalcon_config_object*)zend_objects_get_address(zobj TSRMLS_CC); +} + +static void phalcon_config_construct_internal(zval *this_ptr, zval *array_config TSRMLS_DC); + +static int phalcon_config_count_elements(zval *object, long int *count TSRMLS_DC) +{ + phalcon_config_object* obj = fetchPhalconConfigObject(object TSRMLS_CC); + *count = zend_hash_num_elements(obj->props); + return SUCCESS; +} - if (!offset) { +static zval* phalcon_config_read_internal(phalcon_config_object *object, zval *key, int type TSRMLS_DC) +{ + zval **retval; + if (UNEXPECTED(!key)) { return EG(uninitialized_zval_ptr); } - EG(scope) = Z_OBJCE_P(object); - ret = zend_get_std_object_handlers()->read_property(object, offset, type ZLK_NULL_CC TSRMLS_CC); - EG(scope) = old_scope; - - return ret; + retval = phalcon_hash_get(object->props, key, type); + return retval ? *retval : NULL; } -static zval* phalcon_config_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) +static zval* phalcon_config_read_property(zval *object, zval *offset, int type ZLK_DC TSRMLS_DC) { - zend_object *obj = zend_objects_get_address(object TSRMLS_CC); + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); - if (obj->ce->type != ZEND_INTERNAL_CLASS) { - return zend_get_std_object_handlers()->read_dimension(object, offset, type TSRMLS_CC); + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + return zend_get_std_object_handlers()->read_property(object, offset, type ZLK_CC TSRMLS_CC); } - return phalcon_config_read_dimension_internal(object, offset, type TSRMLS_CC); + return phalcon_config_read_internal(obj, offset, type TSRMLS_CC); } -static void phalcon_config_write_dimension_internal(zval *object, zval *offset, zval *value TSRMLS_DC) +static zval* phalcon_config_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) { - zval* ret; - zend_class_entry *old_scope = EG(scope); + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); - if (!offset) { - return; + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + return zend_get_std_object_handlers()->read_dimension(object, offset, type TSRMLS_CC); } - if (Z_TYPE_P(offset) != IS_STRING) { - zend_throw_exception(phalcon_config_exception_ce, "Index key must be string", 0 TSRMLS_CC); - return; - } + return phalcon_config_read_internal(obj, offset, type TSRMLS_CC); +} - EG(scope) = Z_OBJCE_P(object); +static void phalcon_config_write_internal(phalcon_config_object *object, zval *offset, zval *value TSRMLS_DC) +{ if (Z_TYPE_P(value) == IS_ARRAY) { - zval *tmp, *dummy; - ALLOC_ZVAL(tmp); - object_init_ex(tmp, phalcon_config_ce); - MAKE_STD_ZVAL(dummy); - phalcon_config_construct_internal(dummy, tmp, value TSRMLS_CC); - zval_ptr_dtor(&dummy); - zend_get_std_object_handlers()->write_property(object, offset, value ZLK_NULL_CC TSRMLS_CC); - zval_ptr_dtor(&tmp); + zval *instance; + ALLOC_INIT_ZVAL(instance); + object_init_ex(instance, phalcon_config_ce); + phalcon_config_construct_internal(instance, value TSRMLS_CC); + phalcon_hash_update_or_insert(object->props, offset, instance); } else { - zend_get_std_object_handlers()->write_property(object, offset, value ZLK_NULL_CC TSRMLS_CC); + Z_ADDREF_P(value); + phalcon_hash_update_or_insert(object->props, offset, value); } +} - EG(scope) = old_scope; +static void phalcon_config_write_property(zval *object, zval *offset, zval *value ZLK_DC TSRMLS_DC) +{ + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); + + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + zend_get_std_object_handlers()->write_property(object, offset, value ZLK_CC TSRMLS_CC); + } + + phalcon_config_write_internal(obj, offset, value TSRMLS_CC); } static void phalcon_config_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) { - zend_object *obj = zend_objects_get_address(object TSRMLS_CC); + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); - if (obj->ce->type != ZEND_INTERNAL_CLASS) { + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { zend_get_std_object_handlers()->write_dimension(object, offset, value TSRMLS_CC); } - phalcon_config_write_dimension_internal(object, offset, value TSRMLS_CC); + phalcon_config_write_internal(obj, offset, value TSRMLS_CC); +} + +static int phalcon_config_has_internal(phalcon_config_object *object, zval *key, int check_empty TSRMLS_DC) +{ + zval **tmp = phalcon_hash_get(object->props, key, BP_VAR_NA); + + if (!tmp) { + return 0; + } + + if (0 == check_empty) { + return Z_TYPE_PP(tmp) != IS_NULL; + } + + if (1 == check_empty) { + return zend_is_true(*tmp); + } + + return 1; } -static int phalcon_config_has_dimension_internal(zval *object, zval *offset, int check_empty TSRMLS_DC) +static int phalcon_config_has_property(zval *object, zval *offset, int has_set_exists ZLK_DC TSRMLS_DC) { - int ret; - zend_class_entry *old_scope = EG(scope); + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); - EG(scope) = Z_OBJCE_P(object); - ret = zend_get_std_object_handlers()->has_property(object, offset, check_empty ZLK_NULL_CC TSRMLS_CC); - EG(scope) = old_scope; + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + return zend_get_std_object_handlers()->has_property(object, offset, has_set_exists ZLK_CC TSRMLS_CC); + } - return ret; + return phalcon_config_has_internal(obj, offset, 2 TSRMLS_CC); } static int phalcon_config_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) { - zend_object *obj = zend_objects_get_address(object TSRMLS_CC); + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); - if (obj->ce->type != ZEND_INTERNAL_CLASS) { + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { return zend_get_std_object_handlers()->has_dimension(object, offset, check_empty TSRMLS_CC); } - return phalcon_config_has_dimension_internal(object, offset, check_empty TSRMLS_CC); + return phalcon_config_has_internal(obj, offset, check_empty TSRMLS_CC); +} + +static void phalcon_config_unset_internal(phalcon_config_object *obj, zval *key TSRMLS_DC) +{ + phalcon_hash_unset(obj->props, key); +} + +static void phalcon_config_unset_property(zval *object, zval *member ZLK_DC TSRMLS_DC) +{ + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); + + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + zend_get_std_object_handlers()->unset_property(object, member ZLK_CC TSRMLS_CC); + } + + phalcon_config_unset_internal(obj, member TSRMLS_CC); +} + +static void phalcon_config_unset_dimension(zval *object, zval *offset TSRMLS_DC) +{ + phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); + + if (obj->obj.ce->type != ZEND_INTERNAL_CLASS) { + zend_get_std_object_handlers()->unset_dimension(object, offset TSRMLS_CC); + } + + phalcon_config_unset_internal(obj, offset TSRMLS_CC); +} + + +static HashTable* phalcon_config_get_properties(zval* object TSRMLS_DC) +{ + phalcon_config_object* obj = fetchPhalconConfigObject(object TSRMLS_CC); + HashTable* props = zend_std_get_properties(object TSRMLS_CC); + zval *tmp; + + zend_hash_copy(props, obj->props, (copy_ctor_func_t)zval_add_ref, (void*)&tmp, sizeof(zval*)); + return props; +} + +static int phalcon_config_compare_objects(zval *object1, zval *object2 TSRMLS_DC) +{ + phalcon_config_object *zobj1, *zobj2; + zval result; + + zobj1 = fetchPhalconConfigObject(object1 TSRMLS_CC); + zobj2 = fetchPhalconConfigObject(object2 TSRMLS_CC); + + if (zobj1->obj.ce != zobj2->obj.ce) { + return 1; + } + + if (zobj1->props == zobj2->props) { + return 0; + } + + zend_compare_symbol_tables(&result, zobj1->props, zobj2->props TSRMLS_CC); + assert(Z_TYPE_P(&result) == IS_LONG); + return Z_LVAL_P(&result); +} + +static void phalcon_config_object_dtor(void* v TSRMLS_DC) +{ + phalcon_config_object* obj = v; + + if (obj->props) { + zend_hash_destroy(obj->props); + FREE_HASHTABLE(obj->props); + } + + zend_object_std_dtor(&(obj->obj) TSRMLS_CC); + efree(obj); +} + +static zend_object_value phalcon_config_object_ctor(zend_class_entry* ce TSRMLS_DC) +{ + phalcon_config_object* obj = ecalloc(1, sizeof(phalcon_config_object)); + zend_object_value retval; + + zend_object_std_init(&(obj->obj), ce TSRMLS_CC); + retval.handle = zend_objects_store_put( + obj, + (zend_objects_store_dtor_t)zend_objects_destroy_object, + phalcon_config_object_dtor, + NULL TSRMLS_CC + ); + + retval.handlers = &phalcon_config_object_handlers; + + return retval; } /** @@ -169,67 +305,70 @@ PHALCON_INIT_CLASS(Phalcon_Config){ PHALCON_REGISTER_CLASS(Phalcon, Config, config, phalcon_config_method_entry, 0); + phalcon_config_ce->create_object = phalcon_config_object_ctor; + phalcon_config_object_handlers = *zend_get_std_object_handlers(); + phalcon_config_object_handlers.count_elements = phalcon_config_count_elements; + phalcon_config_object_handlers.read_property = phalcon_config_read_property; + phalcon_config_object_handlers.write_property = phalcon_config_write_property; + phalcon_config_object_handlers.unset_property = phalcon_config_unset_property; + phalcon_config_object_handlers.has_property = phalcon_config_has_property; phalcon_config_object_handlers.read_dimension = phalcon_config_read_dimension; phalcon_config_object_handlers.write_dimension = phalcon_config_write_dimension; + phalcon_config_object_handlers.unset_dimension = phalcon_config_unset_dimension; phalcon_config_object_handlers.has_dimension = phalcon_config_has_dimension; + phalcon_config_object_handlers.get_properties = phalcon_config_get_properties; + phalcon_config_object_handlers.compare_objects = phalcon_config_compare_objects; - zend_class_implements(phalcon_config_ce TSRMLS_CC, 1, zend_ce_arrayaccess); + zend_class_implements(phalcon_config_ce TSRMLS_CC, 2, zend_ce_arrayaccess, spl_ce_Countable); return SUCCESS; } -void phalcon_config_construct_internal(zval *return_value, zval* this_ptr, zval *array_config TSRMLS_DC) +void phalcon_config_construct_internal(zval* this_ptr, zval *array_config TSRMLS_DC) { - zval *value = NULL, *key = NULL, *config_value = NULL; HashTable *ah0; HashPosition hp0; zval **hd; + phalcon_config_object* obj; - PHALCON_MM_GROW(); + if (!array_config || Z_TYPE_P(array_config) == IS_NULL) { + obj = fetchPhalconConfigObject(getThis() TSRMLS_CC); + ALLOC_HASHTABLE(obj->props); + zend_hash_init(obj->props, 0, NULL, ZVAL_PTR_DTOR, 0); + return; + } phalcon_is_iterable(array_config, &ah0, &hp0, 0, 0); - while (zend_hash_get_current_data_ex(ah0, (void**) &hd, &hp0) == SUCCESS) { + obj = fetchPhalconConfigObject(getThis() TSRMLS_CC); + ALLOC_HASHTABLE(obj->props); + zend_hash_init(obj->props, zend_hash_num_elements(Z_ARRVAL_P(array_config)), NULL, ZVAL_PTR_DTOR, 0); - PHALCON_GET_HKEY(key, ah0, hp0); - PHALCON_GET_HVALUE(value); - - /** - * Phalcon\Config does not support numeric keys as properties - */ - if (Z_TYPE_P(key) != IS_STRING) { - PHALCON_THROW_EXCEPTION_STR(phalcon_config_exception_ce, "Only string keys are allowed as configuration properties"); - return; - } - if (Z_TYPE_P(value) == IS_ARRAY) { + while (zend_hash_get_current_data_ex(ah0, (void**) &hd, &hp0) == SUCCESS) { - /** - * Check if sub-arrays contains numeric keys - */ - if (!phalcon_has_numeric_keys(value)) { - zval *dummy; - MAKE_STD_ZVAL(dummy); - - PHALCON_INIT_NVAR(config_value); - object_init_ex(config_value, phalcon_config_ce); - phalcon_config_construct_internal(dummy, config_value, value TSRMLS_CC); - phalcon_update_property_zval_zval(this_ptr, key, config_value TSRMLS_CC); - zval_ptr_dtor(&dummy); - } else { - phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); - } - } else { - /** - * Assign normal keys as properties - */ - phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); - } + zval key = phalcon_get_current_key_w(ah0, &hp0); + phalcon_config_write_internal(obj, &key, *hd TSRMLS_CC); zend_hash_move_forward_ex(ah0, &hp0); } +} - PHALCON_MM_RESTORE(); +static void phalcon_config_toarray_internal(zval *return_value, zval *this_ptr TSRMLS_DC) +{ + phalcon_config_object *obj = fetchPhalconConfigObject(this_ptr TSRMLS_CC); + + if (likely(obj->obj.ce == phalcon_config_ce)) { + zval *tmp; + array_init_size(return_value, zend_hash_num_elements(obj->props)); + zend_hash_copy(Z_ARRVAL_P(return_value), obj->props, (copy_ctor_func_t)zval_add_ref, (void*)&tmp, sizeof(zval*)); + } + else if (phalcon_method_exists_ex(this_ptr, SS("toarray") TSRMLS_CC) == SUCCESS) { + phalcon_call_method(return_value, this_ptr, "toarray"); + } + else { + phalcon_call_func(return_value, "get_object_vars"); + } } /** @@ -243,23 +382,15 @@ PHP_METHOD(Phalcon_Config, __construct){ phalcon_fetch_params(0, 0, 1, &array_config); - if (!array_config) { - PHALCON_INIT_VAR(array_config); - } - /** * Throw exceptions if bad parameters are passed */ - if (Z_TYPE_P(array_config) != IS_ARRAY) { - if (Z_TYPE_P(array_config) != IS_NULL) { - PHALCON_THROW_EXCEPTION_STRW(phalcon_config_exception_ce, "The configuration must be an Array"); - return; - } - - RETURN_NULL(); + if (array_config && Z_TYPE_P(array_config) != IS_ARRAY && Z_TYPE_P(array_config) != IS_NULL) { + PHALCON_THROW_EXCEPTION_STRW(phalcon_config_exception_ce, "The configuration must be an Array"); + return; } - - phalcon_config_construct_internal(return_value, getThis(), array_config TSRMLS_CC); + + phalcon_config_construct_internal(getThis(), array_config TSRMLS_CC); } /** @@ -277,7 +408,7 @@ PHP_METHOD(Phalcon_Config, offsetExists){ zval *index; phalcon_fetch_params(0, 1, 0, &index); - RETURN_BOOL(phalcon_config_has_dimension_internal(getThis(), index, 0 TSRMLS_CC)); + RETURN_BOOL(phalcon_config_has_internal(fetchPhalconConfigObject(getThis() TSRMLS_CC), index, 0 TSRMLS_CC)); } /** @@ -297,20 +428,17 @@ PHP_METHOD(Phalcon_Config, get){ zval *index, *default_value = NULL, *value; phalcon_fetch_params(0, 1, 1, &index, &default_value); - - if (phalcon_config_has_dimension_internal(this_ptr, index, 0 TSRMLS_CC)) { - - value = phalcon_config_read_dimension_internal(getThis(), index, BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(value) != IS_NULL) { - RETURN_CCTORW(value); + + value = phalcon_config_read_internal(fetchPhalconConfigObject(getThis() TSRMLS_CC), index, BP_VAR_NA TSRMLS_CC); + if (!value || Z_TYPE_P(value) == IS_NULL) { + if (default_value) { + RETURN_ZVAL(default_value, 1, 0); } - } - if (default_value) { - RETURN_CCTORW(default_value); + RETURN_NULL(); } - RETURN_NULL(); + RETURN_ZVAL(value, 1, 0); } /** @@ -330,7 +458,7 @@ PHP_METHOD(Phalcon_Config, offsetGet){ phalcon_fetch_params(0, 1, 0, &index); - retval = phalcon_config_read_dimension_internal(getThis(), index, BP_VAR_R TSRMLS_CC); + retval = phalcon_config_read_internal(fetchPhalconConfigObject(getThis() TSRMLS_CC), index, BP_VAR_R TSRMLS_CC); RETURN_ZVAL(retval, 1, 0); } @@ -349,7 +477,7 @@ PHP_METHOD(Phalcon_Config, offsetSet){ zval *index, *value; phalcon_fetch_params(0, 2, 0, &index, &value); - phalcon_config_write_dimension_internal(getThis(), index, value TSRMLS_CC); + phalcon_config_write_internal(fetchPhalconConfigObject(getThis() TSRMLS_CC), index, value TSRMLS_CC); } /** @@ -366,13 +494,7 @@ PHP_METHOD(Phalcon_Config, offsetUnset){ zval *index; phalcon_fetch_params(0, 1, 0, &index); -#if PHP_VERSION_ID < 50400 - Z_OBJ_HANDLER_P(getThis(), unset_property)(getThis(), index TSRMLS_CC); -#else - Z_OBJ_HANDLER_P(getThis(), unset_property)(getThis(), index, 0 TSRMLS_CC); -#endif - - RETURN_TRUE; + phalcon_config_unset_internal(fetchPhalconConfigObject(getThis() TSRMLS_CC), index TSRMLS_CC); } /** @@ -387,78 +509,61 @@ PHP_METHOD(Phalcon_Config, offsetUnset){ */ PHP_METHOD(Phalcon_Config, merge){ - zval *config, *array_config, *value = NULL, *key = NULL, *active_value = NULL; - zval *other_array = NULL; + zval *config, *array_config, *value = NULL, key, *active_value = NULL; HashTable *ah0; HashPosition hp0; zval **hd; + phalcon_config_object *obj; - PHALCON_MM_GROW(); - - phalcon_fetch_params(1, 1, 0, &config); + phalcon_fetch_params(0, 1, 0, &config); if (Z_TYPE_P(config) != IS_OBJECT) { - PHALCON_THROW_EXCEPTION_STR(phalcon_config_exception_ce, "Configuration must be an Object"); + PHALCON_THROW_EXCEPTION_STRW(phalcon_config_exception_ce, "Configuration must be an Object"); return; } - - PHALCON_INIT_VAR(array_config); - phalcon_call_func_p1(array_config, "get_object_vars", config); + + PHALCON_MM_GROW(); + ALLOC_INIT_ZVAL(array_config); + phalcon_config_toarray_internal(array_config, config TSRMLS_CC); phalcon_is_iterable(array_config, &ah0, &hp0, 0, 0); + obj = fetchPhalconConfigObject(getThis() TSRMLS_CC); + while (zend_hash_get_current_data_ex(ah0, (void**) &hd, &hp0) == SUCCESS) { - PHALCON_GET_HKEY(key, ah0, hp0); + key = phalcon_get_current_key_w(ah0, &hp0); PHALCON_GET_HVALUE(value); - if (phalcon_isset_property_zval(this_ptr, key TSRMLS_CC)) { - - /** - * The key is already defined in the object, we have to merge it - */ - PHALCON_OBS_NVAR(active_value); - phalcon_read_property_zval(&active_value, this_ptr, key, PH_NOISY_CC); + active_value = phalcon_config_read_internal(obj, &key, BP_VAR_NA TSRMLS_CC); + /** + * The key is already defined in the object, we have to merge it + */ + if (active_value) { if (Z_TYPE_P(value) == IS_OBJECT && Z_TYPE_P(active_value) == IS_OBJECT) { if (phalcon_method_exists_ex(active_value, SS("merge") TSRMLS_CC) == SUCCESS) { /* Path AAA in the test */ phalcon_call_method_p1_noret(active_value, "merge", value); } else { /* Path AAB in the test */ - phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); + phalcon_config_write_internal(obj, &key, value TSRMLS_CC); } } - else if (Z_TYPE_P(value) == IS_OBJECT && Z_TYPE_P(active_value) == IS_ARRAY) { /* Path AB in the test */ - PHALCON_INIT_NVAR(other_array); - phalcon_call_func_p1(other_array, "get_object_vars", value); - phalcon_array_merge_recursive_n(&active_value, other_array); - phalcon_update_property_zval_zval(this_ptr, key, active_value TSRMLS_CC); - } - else if (Z_TYPE_P(value) == IS_ARRAY && Z_TYPE_P(active_value) == IS_OBJECT) { /* Path AC in the test */ - PHALCON_INIT_NVAR(other_array); - phalcon_call_func_p1(other_array, "get_object_vars", active_value); - phalcon_array_merge_recursive_n(&other_array, value); - phalcon_update_property_zval_zval(this_ptr, key, other_array TSRMLS_CC); - } - else if (Z_TYPE_P(value) == IS_ARRAY && Z_TYPE_P(active_value) == IS_ARRAY) { /* Path AD in the test */ - phalcon_array_merge_recursive_n(&active_value, value); - phalcon_update_property_zval_zval(this_ptr, key, active_value TSRMLS_CC); - } else { /* Path AE in the test */ - phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); + phalcon_config_write_internal(obj, &key, value TSRMLS_CC); } } else { /* Path B in the test */ /** * The key is not defined in the object, add it */ - phalcon_update_property_zval_zval(this_ptr, key, value TSRMLS_CC); + phalcon_config_write_internal(obj, &key, value TSRMLS_CC); } zend_hash_move_forward_ex(ah0, &hp0); } - + zval_ptr_dtor(&array_config); PHALCON_MM_RESTORE(); } @@ -473,17 +578,18 @@ PHP_METHOD(Phalcon_Config, merge){ */ PHP_METHOD(Phalcon_Config, toArray){ - zval *array_config, *value = NULL, *key = NULL, *array_value = NULL; + zval *value = NULL, *key = NULL, *array_value = NULL, *tmp; HashTable *ah0; HashPosition hp0; zval **hd; + phalcon_config_object *obj = fetchPhalconConfigObject(getThis() TSRMLS_CC); PHALCON_MM_GROW(); - PHALCON_INIT_VAR(array_config); - phalcon_call_func_p1(array_config, "get_object_vars", this_ptr); - - phalcon_is_iterable(array_config, &ah0, &hp0, 1, 0); + array_init_size(return_value, zend_hash_num_elements(obj->props)); + zend_hash_copy(Z_ARRVAL_P(return_value), obj->props, (copy_ctor_func_t)zval_add_ref, (void*)&tmp, sizeof(zval*)); + + phalcon_is_iterable(return_value, &ah0, &hp0, 0, 0); while (zend_hash_get_current_data_ex(ah0, (void**) &hd, &hp0) == SUCCESS) { @@ -494,16 +600,22 @@ PHP_METHOD(Phalcon_Config, toArray){ if (phalcon_method_exists_ex(value, SS("toarray") TSRMLS_CC) == SUCCESS) { PHALCON_INIT_NVAR(array_value); phalcon_call_method(array_value, value, "toarray"); - phalcon_array_update_zval(&array_config, key, &array_value, PH_COPY | PH_SEPARATE); + phalcon_array_update_zval(&return_value, key, &array_value, PH_COPY | PH_SEPARATE); } } zend_hash_move_forward_ex(ah0, &hp0); } - zend_hash_destroy(ah0); - efree(ah0); - RETURN_CCTOR(array_config); + RETURN_MM(); +} + +PHP_METHOD(Phalcon_Config, count) +{ + long int cnt; + + phalcon_config_count_elements(getThis(), &cnt TSRMLS_CC); + RETURN_LONG(cnt); } /** @@ -514,12 +626,10 @@ PHP_METHOD(Phalcon_Config, toArray){ */ PHP_METHOD(Phalcon_Config, __set_state){ - zval *data, *tmp; + zval *data; phalcon_fetch_params(0, 1, 0, &data); - MAKE_STD_ZVAL(tmp); object_init_ex(return_value, phalcon_config_ce); - phalcon_config_construct_internal(tmp, return_value, data TSRMLS_CC); - zval_ptr_dtor(&tmp); + phalcon_config_construct_internal(return_value, data TSRMLS_CC); } diff --git a/ext/pconfig.h b/ext/pconfig.h index c2365b3c5e7..d2be9569896 100644 --- a/ext/pconfig.h +++ b/ext/pconfig.h @@ -29,6 +29,7 @@ PHP_METHOD(Phalcon_Config, offsetSet); PHP_METHOD(Phalcon_Config, offsetUnset); PHP_METHOD(Phalcon_Config, merge); PHP_METHOD(Phalcon_Config, toArray); +PHP_METHOD(Phalcon_Config, count); PHP_METHOD(Phalcon_Config, __set_state); ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_config___construct, 0, 0, 0) @@ -61,6 +62,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_config_merge, 0, 0, 1) ZEND_ARG_INFO(0, config) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_config_toarray, 0, 0, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_config_count, 0, 0, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_config___set_state, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO() @@ -73,8 +80,12 @@ PHALCON_INIT_FUNCS(phalcon_config_method_entry){ PHP_ME(Phalcon_Config, offsetSet, arginfo_phalcon_config_offsetset, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Config, offsetUnset, arginfo_phalcon_config_offsetunset, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Config, merge, arginfo_phalcon_config_merge, ZEND_ACC_PUBLIC) - PHP_ME(Phalcon_Config, toArray, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Phalcon_Config, __set_state, arginfo_phalcon_config___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(Phalcon_Config, toArray, arginfo_phalcon_config_toarray, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Config, count, arginfo_phalcon_config_count, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Config, __set_state, arginfo_phalcon_config___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_MALIAS(Phalcon_Config, __get, offsetGet, arginfo_phalcon_config_offsetget, ZEND_ACC_PUBLIC) + PHP_MALIAS(Phalcon_Config, __set, offsetSet, arginfo_phalcon_config_offsetset, ZEND_ACC_PUBLIC) + PHP_MALIAS(Phalcon_Config, __isset, offsetExists, arginfo_phalcon_config_offsetexists, ZEND_ACC_PUBLIC) PHP_FE_END }; From c11f65ac4bfa5ce989bbb3faac19b8b31235a378 Mon Sep 17 00:00:00 2001 From: Vladimir Kolesnikov Date: Sat, 13 Jul 2013 19:25:15 +0300 Subject: [PATCH 6/6] Added comments --- ext/config.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-- ext/kernel/hash.c | 45 ++++++++++++++++++++++++++++++------------ 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/ext/config.c b/ext/config.c index aecd2e82d6f..3d3274c229a 100755 --- a/ext/config.c +++ b/ext/config.c @@ -90,6 +90,9 @@ static inline phalcon_config_object* fetchPhalconConfigObject(zval* zobj TSRMLS_ static void phalcon_config_construct_internal(zval *this_ptr, zval *array_config TSRMLS_DC); +/** + * @brief Counts the number of elements in the configuration; this is the part of Countable interface + */ static int phalcon_config_count_elements(zval *object, long int *count TSRMLS_DC) { phalcon_config_object* obj = fetchPhalconConfigObject(object TSRMLS_CC); @@ -97,6 +100,9 @@ static int phalcon_config_count_elements(zval *object, long int *count TSRMLS_DC return SUCCESS; } +/** + * @brief Common part of @c __get() and @c offsetGet() + */ static zval* phalcon_config_read_internal(phalcon_config_object *object, zval *key, int type TSRMLS_DC) { zval **retval; @@ -108,6 +114,9 @@ static zval* phalcon_config_read_internal(phalcon_config_object *object, zval *k return retval ? *retval : NULL; } +/** + * @brief @c read_property handler, used instead of @c __get() magic method + */ static zval* phalcon_config_read_property(zval *object, zval *offset, int type ZLK_DC TSRMLS_DC) { phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); @@ -119,6 +128,9 @@ static zval* phalcon_config_read_property(zval *object, zval *offset, int type Z return phalcon_config_read_internal(obj, offset, type TSRMLS_CC); } +/** + * @brief @c read_dimension handler, used instead of @c offsetGet() method + */ static zval* phalcon_config_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) { phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); @@ -130,6 +142,9 @@ static zval* phalcon_config_read_dimension(zval *object, zval *offset, int type return phalcon_config_read_internal(obj, offset, type TSRMLS_CC); } +/** + * @brief Common part of @c __set() and @c offsetSet() + */ static void phalcon_config_write_internal(phalcon_config_object *object, zval *offset, zval *value TSRMLS_DC) { if (Z_TYPE_P(value) == IS_ARRAY) { @@ -145,6 +160,9 @@ static void phalcon_config_write_internal(phalcon_config_object *object, zval *o } } +/** + * @brief @c write_property handler, used instead of @c __set() magic method + */ static void phalcon_config_write_property(zval *object, zval *offset, zval *value ZLK_DC TSRMLS_DC) { phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); @@ -156,6 +174,9 @@ static void phalcon_config_write_property(zval *object, zval *offset, zval *valu phalcon_config_write_internal(obj, offset, value TSRMLS_CC); } +/** + * @brief @c write_dimension handler, used instead of @c offsetSet() method + */ static void phalcon_config_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) { phalcon_config_object *obj = fetchPhalconConfigObject(object TSRMLS_CC); @@ -167,6 +188,9 @@ static void phalcon_config_write_dimension(zval *object, zval *offset, zval *val phalcon_config_write_internal(obj, offset, value TSRMLS_CC); } +/** + * @brief Common part of @c __isset() and @c offsetExists() + */ static int phalcon_config_has_internal(phalcon_config_object *object, zval *key, int check_empty TSRMLS_DC) { zval **tmp = phalcon_hash_get(object->props, key, BP_VAR_NA); @@ -208,6 +232,9 @@ static int phalcon_config_has_dimension(zval *object, zval *offset, int check_em return phalcon_config_has_internal(obj, offset, check_empty TSRMLS_CC); } +/** + * @brief Common part of @c __unset() and @c offsetUnset() + */ static void phalcon_config_unset_internal(phalcon_config_object *obj, zval *key TSRMLS_DC) { phalcon_hash_unset(obj->props, key); @@ -235,7 +262,9 @@ static void phalcon_config_unset_dimension(zval *object, zval *offset TSRMLS_DC) phalcon_config_unset_internal(obj, offset TSRMLS_CC); } - +/** + * @brief Returns the list of all internal properties. Used by @c print_r() and other functions + */ static HashTable* phalcon_config_get_properties(zval* object TSRMLS_DC) { phalcon_config_object* obj = fetchPhalconConfigObject(object TSRMLS_CC); @@ -246,6 +275,9 @@ static HashTable* phalcon_config_get_properties(zval* object TSRMLS_DC) return props; } +/** + * @brief Fast object compare function + */ static int phalcon_config_compare_objects(zval *object1, zval *object2 TSRMLS_DC) { phalcon_config_object *zobj1, *zobj2; @@ -267,6 +299,9 @@ static int phalcon_config_compare_objects(zval *object1, zval *object2 TSRMLS_DC return Z_LVAL_P(&result); } +/** + * @brief Frees all memory associated with @c phalcon_config_object + */ static void phalcon_config_object_dtor(void* v TSRMLS_DC) { phalcon_config_object* obj = v; @@ -280,6 +315,9 @@ static void phalcon_config_object_dtor(void* v TSRMLS_DC) efree(obj); } +/** + * @brief Constructs @c phalcon_config_object + */ static zend_object_value phalcon_config_object_ctor(zend_class_entry* ce TSRMLS_DC) { phalcon_config_object* obj = ecalloc(1, sizeof(phalcon_config_object)); @@ -325,6 +363,10 @@ PHALCON_INIT_CLASS(Phalcon_Config){ return SUCCESS; } +/** + * Internal implementation of __construct(). Used to avoid calls to userspace when + * recursively walking the configuration array. Does not use MM. + */ void phalcon_config_construct_internal(zval* this_ptr, zval *array_config TSRMLS_DC) { HashTable *ah0; @@ -354,6 +396,10 @@ void phalcon_config_construct_internal(zval* this_ptr, zval *array_config TSRMLS } } +/** + * Internal implementation of non-recursive @c toArray(). Used as an alternative + * to @c get_object_properties(). + */ static void phalcon_config_toarray_internal(zval *return_value, zval *this_ptr TSRMLS_DC) { phalcon_config_object *obj = fetchPhalconConfigObject(this_ptr TSRMLS_CC); @@ -606,7 +652,7 @@ PHP_METHOD(Phalcon_Config, toArray){ zend_hash_move_forward_ex(ah0, &hp0); } - + RETURN_MM(); } diff --git a/ext/kernel/hash.c b/ext/kernel/hash.c index 421deb576a0..3271104a147 100644 --- a/ext/kernel/hash.c +++ b/ext/kernel/hash.c @@ -180,6 +180,15 @@ int phalcon_has_numeric_keys(const zval *data) return 0; } +/** + * @brief Adds or updates item @a key in the hash table @a ht + * @param ht Hash table + * @param[in] key Key + * @param[in] value Value + * @note @a value's reference count in not updated + * @note If @a key is @c NULL or is @c IS_NULL, @a value is appended to @a ht + * @throw E_WARNING if @a key type is not supported + */ void phalcon_hash_update_or_insert(HashTable *ht, zval *key, zval *value) { if (!key || Z_TYPE_P(key) == IS_NULL) { @@ -206,16 +215,20 @@ void phalcon_hash_update_or_insert(HashTable *ht, zval *key, zval *value) } /** - * @brief Gets an entry from @a ht identified by @a key and puts it to @a *value + * @brief Returns the entry @a ht identified by @a key * @param[in] ht Hash table - * @param[in] offset - * @param[out] value - * @return - * @retval @c SUCCESS - * @retval @c FAILURE - * @throw @c E_WARNING when @a key is of not supported type - * @note @a *value is not modified on failure - * @note Reference count of the retrieved item is not modified + * @param[in] key + * @param[in] type One of @c BP_VAR_XXX values + * @return Pointer to the stored value or a pointer to the special variable / @c NULL if @a key was not found + * @retval &EG(error_zval_ptr) when @a key was not found and @a type is one of @c BP_VAR_W, @c BP_VAR_RW + * @retval &EG(uninitialized_zval_ptr) when @a key was not found and @a type is one of @c BP_VAR_R, @c BP_VAR_UNSET, @c BP_VAR_IS + * @retval @c NULL when @a key was not found and @a type is not any of the above + * @throw @c E_WARNING when @a key is of not supported typel in this case the function never returns @c NULL + * @throw @c E_STRICT when @a key is a resource + * @throw @c E_NOTICE if @a key was not found and @a type is @c BP_VAR_R or @c BP_VAR_RW + * @note Reference count of the returned item is not modified + * @note The implementation is suitable for @c read_property, @c get_property_ptr_ptr and @c read_dimension object handlers + * @warning If @a type is @c BP_VAR_W or @c BP_VAR_RW and @a key was not found, it is added to @a ht and its value is set to @c IS_NULL */ zval** phalcon_hash_get(HashTable *ht, const zval *key, int type) { @@ -291,17 +304,23 @@ zval** phalcon_hash_get(HashTable *ht, const zval *key, int type) } } -int phalcon_hash_unset(HashTable *ht, zval *offset) +/** + * @brief Unset @a key from @a ht + * @param ht + * @param key + * @return + */ +int phalcon_hash_unset(HashTable *ht, zval *key) { - switch (Z_TYPE_P(offset)) { + switch (Z_TYPE_P(key)) { case IS_LONG: case IS_DOUBLE: case IS_BOOL: case IS_RESOURCE: - return (zend_hash_index_del(ht, (Z_TYPE_P(offset) == IS_DOUBLE) ? ((long int)Z_DVAL_P(offset)) : Z_LVAL_P(offset)) == SUCCESS); + return (zend_hash_index_del(ht, (Z_TYPE_P(key) == IS_DOUBLE) ? ((long int)Z_DVAL_P(key)) : Z_LVAL_P(key)) == SUCCESS); case IS_STRING: - return (zend_symtable_del(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == SUCCESS); + return (zend_symtable_del(ht, Z_STRVAL_P(key), Z_STRLEN_P(key)+1) == SUCCESS); default: zend_error(E_WARNING, "Illegal offset type");