]> granicus.if.org Git - php/commitdiff
Fix list() destructuring to special variables
authorNikita Popov <nikic@php.net>
Mon, 22 Sep 2014 16:34:09 +0000 (18:34 +0200)
committerNikita Popov <nikic@php.net>
Mon, 22 Sep 2014 16:34:40 +0000 (18:34 +0200)
Zend/tests/list_destructuring_to_special_variables.phpt [new file with mode: 0644]
Zend/zend_compile.c

diff --git a/Zend/tests/list_destructuring_to_special_variables.phpt b/Zend/tests/list_destructuring_to_special_variables.phpt
new file mode 100644 (file)
index 0000000..4418c96
--- /dev/null
@@ -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"
+}
index 7b8004533a9113d2a127856ad98cb62abfa57f4c..a7e12fe9a5b5d63342063478887e5adc96eb2eed 100644 (file)
@@ -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];