diff options
author | Nikita Popov <nikic@php.net> | 2014-09-22 18:34:09 +0200 |
---|---|---|
committer | Nikita Popov <nikic@php.net> | 2014-09-22 18:34:40 +0200 |
commit | f30f28ec47e726d179ee123906a04dcbb8f46900 (patch) | |
tree | 5d77ba228928655b4d9481b62d036f657642c73a | |
parent | 483697617feff9a1746045c0a1fa7967cba35054 (diff) | |
download | php-git-f30f28ec47e726d179ee123906a04dcbb8f46900.tar.gz |
Fix list() destructuring to special variables
-rw-r--r-- | Zend/tests/list_destructuring_to_special_variables.phpt | 49 | ||||
-rw-r--r-- | Zend/zend_compile.c | 31 |
2 files changed, 63 insertions, 17 deletions
diff --git a/Zend/tests/list_destructuring_to_special_variables.phpt b/Zend/tests/list_destructuring_to_special_variables.phpt new file mode 100644 index 0000000000..4418c967c2 --- /dev/null +++ b/Zend/tests/list_destructuring_to_special_variables.phpt @@ -0,0 +1,49 @@ +--TEST-- +list() can be used to destructure to string offsets, __set and ArrayAccess::offsetSet +--FILE-- +<?php + +class Obj { + public $values = []; + public function __set($name, $value) { + $this->values[$name] = $value; + } +} + +class Arr implements ArrayAccess { + public $values = []; + public function offsetSet($name, $value) { + $this->values[$name] = $value; + } + public function offsetGet($name) {} + public function offsetExists($name) {} + public function offsetUnset($name) {} +} + +$str = 'ab'; +list($str[0], $str[1]) = ['x', 'y']; +var_dump($str); + +$obj = new Obj; +list($obj->foo, $obj->bar) = ['foo', 'bar']; +var_dump($obj->values); + +$arr = new Arr; +list($arr['foo'], $arr['bar']) = ['foo', 'bar']; +var_dump($arr->values); + +?> +--EXPECT-- +string(2) "xy" +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 7b8004533a..a7e12fe9a5 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2067,6 +2067,17 @@ static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t /* }}} */ void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC); +void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC); + +static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node TSRMLS_DC) /* {{{ */ +{ + znode dummy_node; + zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast, + zend_ast_create_znode(value_node)); + zend_compile_assign(&dummy_node, assign_ast TSRMLS_CC); + zend_do_free(&dummy_node TSRMLS_CC); +} +/* }}} */ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */ { @@ -2227,7 +2238,7 @@ static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_n for (i = 0; i < list->children; ++i) { zend_ast *var_ast = list->child[i]; - znode fetch_result, dim_node, var_node, assign_result; + znode fetch_result, dim_node; zend_op *opline; if (var_ast == NULL) { @@ -2246,13 +2257,9 @@ static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_n opline->extended_value |= ZEND_FETCH_ADD_LOCK; if (var_ast->kind != ZEND_AST_LIST) { - if (is_this_fetch(var_ast)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); - } - zend_compile_var(&var_node, var_ast, BP_VAR_W TSRMLS_CC); - zend_emit_op(&assign_result, ZEND_ASSIGN, &var_node, &fetch_result TSRMLS_CC); - zend_do_free(&assign_result TSRMLS_CC); + zend_emit_assign_znode(var_ast, &fetch_result TSRMLS_CC); } else { + znode assign_result; zend_compile_list_assign(&assign_result, var_ast, &fetch_result TSRMLS_CC); zend_do_free(&assign_result TSRMLS_CC); } @@ -2357,16 +2364,6 @@ void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ } /* }}} */ -static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node TSRMLS_DC) /* {{{ */ -{ - znode dummy_node; - zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast, - zend_ast_create_znode(value_node)); - zend_compile_assign(&dummy_node, assign_ast TSRMLS_CC); - zend_do_free(&dummy_node TSRMLS_CC); -} -/* }}} */ - void zend_compile_assign_ref(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ { zend_ast *target_ast = ast->child[0]; |