Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Phalcon\Config implementation using object handlers #842

Merged
merged 7 commits into from Jul 13, 2013
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Proof of concept
  • Loading branch information
sjinks committed Jul 13, 2013
commit c64f4119a42cee6692b3613356722491e41e6686
268 changes: 174 additions & 94 deletions ext/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}

/**
Expand All @@ -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));
}

/**
Expand All @@ -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();
}

/**
Expand All @@ -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);
}

/**
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -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);
}
10 changes: 10 additions & 0 deletions ext/php_phalcon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 9 additions & 1 deletion unit-tests/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}