]> granicus.if.org Git - php/commitdiff
Allow specifying keys on list() elements
authorAndrea Faulds <ajf@ajf.me>
Fri, 25 Mar 2016 17:18:42 +0000 (17:18 +0000)
committerAndrea Faulds <ajf@ajf.me>
Fri, 25 Mar 2016 17:18:42 +0000 (17:18 +0000)
Squashed commit of the following:

commit 0361dbe35616722fbe51b446ab7b43a9ca01f455
Author: Andrea Faulds <ajf@ajf.me>
Date:   Fri Mar 25 16:59:20 2016 +0000

    UPGRADING and NEWS

commit dca9d4a36c845bfe4fbcb9db18e184469110ea5a
Author: Andrea Faulds <ajf@ajf.me>
Date:   Fri Mar 25 16:45:18 2016 +0000

    Add tests contributed by @jesseschalken

commit e557f77eab692ed8bb18dbdff48777d80b6f6cbd
Author: Andrea Faulds <ajf@ajf.me>
Date:   Fri Mar 25 16:44:51 2016 +0000

    Rebuild VM

commit 70942e4c3cbb6b4fe6305b27e1e1b2bed78e76df
Author: Andrea Faulds <ajf@ajf.me>
Date:   Wed Feb 24 13:12:26 2016 +0000

    Add test for evaluation order of nested list() keys

commit ed3592e80c5231d9e9a95558aa768a42b75bdebc
Author: Andrea Faulds <ajf@ajf.me>
Date:   Wed Feb 24 12:42:04 2016 +0000

    Add test for evaluation order

commit 589756cbcccbb4702c90b5aa9c091af446058ca1
Author: Andrea Faulds <ajf@ajf.me>
Date:   Tue Jan 19 17:29:34 2016 +0000

    Allow arbitrary expressions for key

commit 3f622077c32fcd82fcf27a41bd0f22e2552ec4c5
Author: Andrea Faulds <ajf@ajf.me>
Date:   Tue Jan 19 17:45:10 2016 +0000

    Remove compile-time HANDLE_NUMERIC (see bug #63217)

commit bab758119aec63289a2c5bef6a5f90a7bc6441a2
Author: Andrea Faulds <ajf@ajf.me>
Date:   Sun Jan 17 01:20:26 2016 +0000

    Handle numeric strings

commit 14bfe93ddc34d1175bccb42a158be8842c472a9c
Author: Andrea Faulds <ajf@ajf.me>
Date:   Sun Jan 17 01:09:36 2016 +0000

    Allow trailing comma

commit f4c8b2cb30fc074b15b5f7aabef5444382403b5d
Author: Andrea Faulds <ajf@ajf.me>
Date:   Sat Jan 16 23:47:11 2016 +0000

    Add tests

commit 0085884a6176c3a981b53131fbb4fa0c44db2670
Author: Andrea Faulds <ajf@ajf.me>
Date:   Sat Jan 16 22:24:23 2016 +0000

    Handle non-integer/string opcodes

commit e572d2d0ada6a64b36a2c6f5e8cb57439f51b55e
Author: Andrea Faulds <ajf@ajf.me>
Date:   Sat Jan 16 21:10:33 2016 +0000

    Disallow mixing keyed and unkeyed list() elements

commit cede13ccfe0c486591fa84764271ac1b8cb90d0b
Author: Andrea Faulds <ajf@ajf.me>
Date:   Sun Jan 10 20:46:44 2016 +0000

    list() with keys (no foreach or tests)

21 files changed:
NEWS
UPGRADING
Zend/tests/foreach_list_keyed.phpt [new file with mode: 0644]
Zend/tests/list_keyed.phpt [new file with mode: 0644]
Zend/tests/list_keyed_ArrayAccess.phpt [new file with mode: 0644]
Zend/tests/list_keyed_conversions.phpt [new file with mode: 0644]
Zend/tests/list_keyed_evaluation_order.inc [new file with mode: 0644]
Zend/tests/list_keyed_evaluation_order.phpt [new file with mode: 0644]
Zend/tests/list_keyed_evaluation_order_2.phpt [new file with mode: 0644]
Zend/tests/list_keyed_evaluation_order_3.phpt [new file with mode: 0644]
Zend/tests/list_keyed_evaluation_order_nested.phpt [new file with mode: 0644]
Zend/tests/list_keyed_non_literals.phpt [new file with mode: 0644]
Zend/tests/list_keyed_trailing_comma.phpt [new file with mode: 0644]
Zend/tests/list_keyed_undefined.phpt [new file with mode: 0644]
Zend/tests/list_mixed_keyed_unkeyed.phpt [new file with mode: 0644]
Zend/tests/list_mixed_nested_keyed_unkeyed.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_language_parser.y
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_opcodes.c

diff --git a/NEWS b/NEWS
index fe4640391560ec508a1e07abe70ad250f5f5daa5..604cf485dd7a3ad71bc01e3b845d7d25e7ccc12c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,7 @@ PHP                                                                        NEWS
   . Added void return type. (Andrea)
   . Added support for negative string offsets in string offset syntax and
     various string functions. (Francois)
+  . Added a form of the list() construct where keys can be specified. (Andrea)
 
 - FTP:
   . Implemented FR #55651 (Option to ignore the returned FTP PASV address).
index fc23e3676f10a72bfc10807bf7c853384b8164a3..a938978d7bf7fbd181646fb8e50ace03bfdf3c1e 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -35,6 +35,8 @@ PHP 7.1 UPGRADE NOTES
   . String offset access now supports negative references, which will be
     counted from the end of the string.
     (RFC: https://wiki.php.net/rfc/negative-string-offsets)
+  . Added a form of the list() construct where keys can be specified.
+    (RFC: https://wiki.php.net/rfc/list_keys)
 
 ========================================
 3. Changes in SAPI modules
diff --git a/Zend/tests/foreach_list_keyed.phpt b/Zend/tests/foreach_list_keyed.phpt
new file mode 100644 (file)
index 0000000..f5fab4e
--- /dev/null
@@ -0,0 +1,36 @@
+--TEST--
+foreach with list syntax, keyed
+--FILE--
+<?php
+
+$points = [
+    ["x" => 1, "y" => 2],
+    ["x" => 2, "y" => 1]
+];
+
+foreach ($points as list("x" => $x, "y" => $y)) {
+    var_dump($x, $y);
+}
+
+echo PHP_EOL;
+
+$invertedPoints = [
+    "x" => [1, 2],
+    "y" => [2, 1]
+];
+
+foreach ($invertedPoints as list(0 => $row1, 1 => $row2)) {
+    var_dump($row1, $row2);
+}
+
+?>
+--EXPECT--
+int(1)
+int(2)
+int(2)
+int(1)
+
+int(1)
+int(2)
+int(2)
+int(1)
diff --git a/Zend/tests/list_keyed.phpt b/Zend/tests/list_keyed.phpt
new file mode 100644 (file)
index 0000000..b549ed9
--- /dev/null
@@ -0,0 +1,71 @@
+--TEST--
+list() with keys
+--FILE--
+<?php
+
+$antonyms = [
+    "good" => "bad",
+    "happy" => "sad",
+];
+
+list("good" => $good_antonym, "happy" => $happy_antonym) = $antonyms;
+var_dump($good_antonym, $happy_antonym);
+
+echo PHP_EOL;
+
+$powersOfTwo = [
+    1 => 2,
+    2 => 4,
+    3 => 8
+];
+
+list(1 => $two_1, 2 => $two_2, 3 => $two_3) = $powersOfTwo;
+var_dump($two_1, $two_2, $two_3);
+
+echo PHP_EOL;
+
+$contrivedMixedKeyTypesExample = [
+    7 => "the best PHP version",
+    "elePHPant" => "the cutest mascot"
+];
+
+list(7 => $seven, "elePHPant" => $elePHPant) = $contrivedMixedKeyTypesExample;
+var_dump($seven, $elePHPant);
+
+echo PHP_EOL;
+
+$allTogetherNow = [
+    "antonyms" => $antonyms,
+    "powersOfTwo" => $powersOfTwo,
+    "contrivedMixedKeyTypesExample" => $contrivedMixedKeyTypesExample
+];
+
+list(
+    "antonyms" => list("good" => $good_antonym, "happy" => $happy_antonym),
+    "powersOfTwo" => list(1 => $two_1, 2 => $two_2, 3 => $two_3),
+    "contrivedMixedKeyTypesExample" => list(7 => $seven, "elePHPant" => $elePHPant)
+) = $allTogetherNow;
+
+var_dump($good_antonym, $happy_antonym);
+var_dump($two_1, $two_2, $two_3);
+var_dump($seven, $elePHPant);
+
+?>
+--EXPECT--
+string(3) "bad"
+string(3) "sad"
+
+int(2)
+int(4)
+int(8)
+
+string(20) "the best PHP version"
+string(17) "the cutest mascot"
+
+string(3) "bad"
+string(3) "sad"
+int(2)
+int(4)
+int(8)
+string(20) "the best PHP version"
+string(17) "the cutest mascot"
diff --git a/Zend/tests/list_keyed_ArrayAccess.phpt b/Zend/tests/list_keyed_ArrayAccess.phpt
new file mode 100644 (file)
index 0000000..1bb2013
--- /dev/null
@@ -0,0 +1,54 @@
+--TEST--
+list() with keys and ArrayAccess
+--FILE--
+<?php
+
+$antonymObject = new ArrayObject;
+$antonymObject["good"] = "bad";
+$antonymObject["happy"] = "sad";
+
+list("good" => $good, "happy" => $happy) = $antonymObject;
+var_dump($good, $happy);
+
+echo PHP_EOL;
+
+$stdClassCollection = new SplObjectStorage;
+$foo = new StdClass;
+$stdClassCollection[$foo] = "foo";
+$bar = new StdClass;
+$stdClassCollection[$bar] = "bar";
+
+list($foo => $fooStr, $bar => $barStr) = $stdClassCollection;
+var_dump($fooStr, $barStr);
+
+echo PHP_EOL;
+
+class IndexPrinter implements ArrayAccess
+{
+    public function offsetGet($offset) {
+        echo "GET ";
+        var_dump($offset);
+    }
+    public function offsetSet($offset, $value) {
+    }
+    public function offsetExists($offset) {
+    }
+    public function offsetUnset($offset) {
+    }
+}
+
+$op = new IndexPrinter;
+list(123 => $x) = $op;
+// PHP shouldn't convert this to an integer offset, because it's ArrayAccess
+list("123" => $x) = $op;
+
+?>
+--EXPECT--
+string(3) "bad"
+string(3) "sad"
+
+string(3) "foo"
+string(3) "bar"
+
+GET int(123)
+GET string(3) "123"
diff --git a/Zend/tests/list_keyed_conversions.phpt b/Zend/tests/list_keyed_conversions.phpt
new file mode 100644 (file)
index 0000000..e2cf91a
--- /dev/null
@@ -0,0 +1,32 @@
+--TEST--
+list() with non-integer-or-string keys
+--FILE--
+<?php
+
+$results = [
+    0 => 0,
+    1 => 1,
+    "" => ""
+];
+
+list(NULL => $NULL, 1.5 => $float, FALSE => $FALSE, TRUE => $TRUE) = $results;
+var_dump($NULL, $float, $FALSE, $TRUE);
+
+echo PHP_EOL;
+
+list("0" => $zeroString, "1" => $oneString) = $results;
+var_dump($zeroString, $oneString);
+
+list(STDIN => $resource) = [];
+
+?>
+--EXPECTF--
+string(0) ""
+int(1)
+int(0)
+int(1)
+
+int(0)
+int(1)
+
+Notice: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d
diff --git a/Zend/tests/list_keyed_evaluation_order.inc b/Zend/tests/list_keyed_evaluation_order.inc
new file mode 100644 (file)
index 0000000..490a6d8
--- /dev/null
@@ -0,0 +1,60 @@
+<?php declare(strict_types=1);
+
+// Observer objects for the Zend/tests/list_keyed_evaluation_order.* tests
+
+class Stringable
+{
+    private $name;
+    public function __construct(string $name) {
+        $this->name = $name;
+    }
+
+    public function __toString(): string {
+        echo "$this->name evaluated.", PHP_EOL;
+        return $this->name;
+    }
+}
+
+class Indexable implements ArrayAccess
+{
+    private $array;
+    public function __construct(array $array) {
+        $this->array = $array;
+    }
+
+    public function offsetExists($offset): bool {
+        echo "Existence of offset $offset checked for.", PHP_EOL;
+        return isset($this->array[$offset]);
+    }
+
+    public function offsetUnset($offset): void {
+        unset($this->array[$offset]);
+        echo "Offset $offset removed.", PHP_EOL;
+    }
+
+    public function offsetGet($offset) {
+        echo "Offset $offset retrieved.", PHP_EOL;
+        return $this->array[$offset];
+    }
+
+    public function offsetSet($offset, $value): void {
+        $this->array[$offset] = $value;
+        echo "Offset $offset set to $value.", PHP_EOL;
+    }
+}
+
+class IndexableRetrievable
+{
+    private $label;
+    private $indexable;
+    
+    public function __construct(string $label, Indexable $indexable) {
+        $this->label = $label;
+        $this->indexable = $indexable;
+    }
+
+    public function getIndexable(): Indexable {
+        echo "Indexable $this->label retrieved.", PHP_EOL;
+        return $this->indexable;
+    }
+}
diff --git a/Zend/tests/list_keyed_evaluation_order.phpt b/Zend/tests/list_keyed_evaluation_order.phpt
new file mode 100644 (file)
index 0000000..0f0652b
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+list() with keys, evaluation order
+--FILE--
+<?php
+
+require_once "list_keyed_evaluation_order.inc";
+
+$a = new Stringable("A");
+$c = new Stringable("C");
+
+$e = new IndexableRetrievable("E", new Indexable(["A" => "value for offset A", "C" => "value for offset C"]));
+
+$store = new Indexable([]);
+
+// list($a => $b, $c => $d) = $e;
+// Should be evaluated in the order:
+// 1. Evaluate $e
+// 2. Evaluate $a
+// 3. Evaluate $e[$a]
+// 4. Assign $b from $e[$a]
+// 5. Evaluate $c
+// 6. Evaluate $e[$c]
+// 7. Assign $c from $e[$a]
+
+list((string)$a => $store["B"], (string)$c => $store["D"]) = $e->getIndexable();
+
+?>
+--EXPECT--
+Indexable E retrieved.
+A evaluated.
+Offset A retrieved.
+Offset B set to value for offset A.
+C evaluated.
+Offset C retrieved.
+Offset D set to value for offset C.
diff --git a/Zend/tests/list_keyed_evaluation_order_2.phpt b/Zend/tests/list_keyed_evaluation_order_2.phpt
new file mode 100644 (file)
index 0000000..ddfba68
--- /dev/null
@@ -0,0 +1,77 @@
+--TEST--
+list() with keys, evaluation order #2
+--FILE--
+<?php
+
+// All the following should print 'a' then 'b'
+
+list($a, $b) = ['a', 'b'];
+var_dump($a);
+var_dump($b);
+
+list(0 => $a, 1 => $b) = ['a', 'b'];
+var_dump($a);
+var_dump($b);
+
+list(1 => $b, 0 => $a) = ['a', 'b'];
+var_dump($a);
+var_dump($b);
+
+$arr = [];
+list($arr[], $arr[]) = ['a', 'b'];
+var_dump($arr[0]);
+var_dump($arr[1]);
+
+$arr = [];
+list(0 => $arr[], 1 => $arr[]) = ['a', 'b'];
+var_dump($arr[0]);
+var_dump($arr[1]);
+
+$arr = [];
+list(1 => $arr[], 0 => $arr[]) = ['b', 'a'];
+var_dump($arr[0]);
+var_dump($arr[1]);
+
+$arr = [];
+list(list(1 => $arr[], 0 => $arr[])) = [['b', 'a']];
+var_dump($arr[0]);
+var_dump($arr[1]);
+
+$arr = [];
+list('key1' => $arr[], 'key2' => $arr[]) = ['key2' => 'b', 'key1' => 'a'];
+var_dump($arr[0]);
+var_dump($arr[1]);
+
+// This should print 'foo'
+$a = 0;
+list($a => $a) = ['foo', 'bar'];
+var_dump($a);
+
+// This should print 'bar' then 'foo'
+$a = 0;
+$b = 1;
+list($b => $a, $a => $c) = ['bar' => 'foo', 1 => 'bar'];
+var_dump($a);
+var_dump($c);
+
+?>
+--EXPECT--
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(3) "foo"
+string(3) "bar"
+string(3) "foo"
diff --git a/Zend/tests/list_keyed_evaluation_order_3.phpt b/Zend/tests/list_keyed_evaluation_order_3.phpt
new file mode 100644 (file)
index 0000000..7850834
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+list() with keys, evaluation order #3
+--FILE--
+<?php
+
+$i = 0;
+$a = [
+    0 => [
+        'b' => 'bar',
+        'a' => 'foo',
+    ],
+    1 => 'a',
+    3 => 'b',
+];
+list($a[$i++] => $a[$i++], $a[$i++] => $a[$i++]) = $a[$i++];
+var_dump($i); // should be 5
+var_dump($a[2]); // should be 'foo'
+var_dump($a[4]); // should be 'bar'
+
+?>
+--EXPECT--
+int(5)
+string(3) "foo"
+string(3) "bar"
diff --git a/Zend/tests/list_keyed_evaluation_order_nested.phpt b/Zend/tests/list_keyed_evaluation_order_nested.phpt
new file mode 100644 (file)
index 0000000..8a7725d
--- /dev/null
@@ -0,0 +1,77 @@
+--TEST--
+list() with keys, evaluation order: nested
+--FILE--
+<?php
+
+require_once "list_keyed_evaluation_order.inc";
+
+$a = new Stringable("A");
+$c = new Stringable("C");
+$f = new Stringable("F");
+$g = new Stringable("G");
+$i = new Stringable("I");
+
+$k = new IndexableRetrievable("K", new Indexable([
+    "A" => "offset value for A",
+    "C" => new Indexable([
+        0 => "offset value for 0",
+        1 => "offset value for 1"
+    ]),
+    "F" => new Indexable([
+        "G" => "offset value for G",
+        "I" => "offset value for I"
+    ])
+]));
+
+$store = new Indexable([]);
+
+// list($a => $b, $c => list($d, $e), $f => list($g => $h, $i => $j)) = $k;
+// Should be evaluated in the order:
+// 1. Evaluate $k
+// 2. Evaluate $a
+// 3. Evaluate $k[$a]
+// 4. Assign $b from $k[$a]
+// 5. Evaluate $c
+// 6. Evaluate $k[$c]
+// 7. Evaluate $k[$c][0]
+// 8. Assign $d from $k[$c][0]
+// 9. Evaluate $k[$c][1]
+// 10. Assign $e from $k[$c][1]
+// 11. Evaluate $f
+// 12. Evaluate $k[$f]
+// 13. Evaluate $g
+// 14. Evaluate $k[$f][$g]
+// 15. Assign $h from $k[$f][$g]
+// 16. Evaluate $i
+// 17. Evaluate $k[$f][$i]
+// 18. Assign $j from $k[$f][$i]
+
+list(
+    (string)$a => $store["B"],
+    (string)$c => list($store["D"], $store["E"]),
+    (string)$f => list(
+        (string)$g => $store["H"],
+        (string)$i => $store["J"]
+    )
+) = $k->getIndexable();
+
+?>
+--EXPECT--
+Indexable K retrieved.
+A evaluated.
+Offset A retrieved.
+Offset B set to offset value for A.
+C evaluated.
+Offset C retrieved.
+Offset 0 retrieved.
+Offset D set to offset value for 0.
+Offset 1 retrieved.
+Offset E set to offset value for 1.
+F evaluated.
+Offset F retrieved.
+G evaluated.
+Offset G retrieved.
+Offset H set to offset value for G.
+I evaluated.
+Offset I retrieved.
+Offset J set to offset value for I.
diff --git a/Zend/tests/list_keyed_non_literals.phpt b/Zend/tests/list_keyed_non_literals.phpt
new file mode 100644 (file)
index 0000000..80f22ed
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+list() with constant keys
+--FILE--
+<?php
+
+$arr = [
+    1 => "one",
+    2 => "two",
+    3 => "three"
+];
+
+const COMPILE_TIME_RESOLVABLE = 1;
+
+define('PROBABLY_NOT_COMPILE_TIME_RESOLVABLE', file_get_contents("data:text/plain,2"));
+
+$probablyNotCompileTimeResolvable3 = cos(0) * 3;
+
+list(
+    COMPILE_TIME_RESOLVABLE => $one,
+    PROBABLY_NOT_COMPILE_TIME_RESOLVABLE => $two,
+    $probablyNotCompileTimeResolvable3 => $three
+) = $arr;
+
+var_dump($one, $two, $three);
+
+?>
+--EXPECTF--
+string(3) "one"
+string(3) "two"
+string(5) "three"
diff --git a/Zend/tests/list_keyed_trailing_comma.phpt b/Zend/tests/list_keyed_trailing_comma.phpt
new file mode 100644 (file)
index 0000000..e0af0ae
--- /dev/null
@@ -0,0 +1,38 @@
+--TEST--
+list() with keys and a trailing comma
+--FILE--
+<?php
+
+$antonyms = [
+    "good" => "bad",
+    "happy" => "sad",
+];
+
+list(
+    "good" => $good,
+    "happy" => $happy
+) = $antonyms;
+
+var_dump($good, $happy);
+
+echo PHP_EOL;
+
+$antonyms = [
+    "good" => "bad",
+    "happy" => "sad",
+];
+
+list(
+    "good" => $good,
+    "happy" => $happy,
+) = $antonyms;
+
+var_dump($good, $happy);
+
+?>
+--EXPECT--
+string(3) "bad"
+string(3) "sad"
+
+string(3) "bad"
+string(3) "sad"
diff --git a/Zend/tests/list_keyed_undefined.phpt b/Zend/tests/list_keyed_undefined.phpt
new file mode 100644 (file)
index 0000000..a18e3b4
--- /dev/null
@@ -0,0 +1,22 @@
+--TEST--
+list() with undefined keys
+--FILE--
+<?php
+
+$contrivedMixedKeyTypesExample = [
+    7 => "the best PHP version",
+    "elePHPant" => "the cutest mascot"
+];
+
+list(5 => $five, "duke" => $duke) = $contrivedMixedKeyTypesExample;
+
+var_dump($five, $duke);
+
+?>
+--EXPECTF--
+
+Notice: Undefined offset: 5 in %s on line %d
+
+Notice: Undefined index: duke in %s on line %d
+NULL
+NULL
diff --git a/Zend/tests/list_mixed_keyed_unkeyed.phpt b/Zend/tests/list_mixed_keyed_unkeyed.phpt
new file mode 100644 (file)
index 0000000..5562479
--- /dev/null
@@ -0,0 +1,16 @@
+--TEST--
+list() with both keyed and unkeyed elements
+--FILE--
+<?php
+
+$contrivedKeyedAndUnkeyedArrayExample = [
+    0,
+    1 => 1,
+    "foo" => "bar"
+];
+
+list($zero, 1 => $one, "foo" => $foo) = $contrivedKeyedAndUnkeyedArrayExample;
+
+?>
+--EXPECTF--
+Parse error: syntax error, unexpected %s in %s on line %d
diff --git a/Zend/tests/list_mixed_nested_keyed_unkeyed.phpt b/Zend/tests/list_mixed_nested_keyed_unkeyed.phpt
new file mode 100644 (file)
index 0000000..3087775
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+list() with nested unkeyed and keyed list()
+--FILE--
+<?php
+
+$points = [
+    ["x" => 1, "y" => 2],
+    ["x" => 2, "y" => 1]
+];
+
+list(list("x" => $x1, "y" => $y1), list("x" => $x2, "y" => $y2)) = $points;
+var_dump($x1, $y1, $x2, $y2);
+
+echo PHP_EOL;
+
+$invertedPoints = [
+    "x" => [1, 2],
+    "y" => [2, 1]
+];
+
+list("x" => list($x1, $x2), "y" => list($y1, $y2)) = $invertedPoints;
+var_dump($x1, $y1, $x2, $y2);
+
+?>
+--EXPECT--
+int(1)
+int(2)
+int(2)
+int(1)
+
+int(1)
+int(2)
+int(2)
+int(1)
index 9b79202014dfffa036e5c3609cc61e129f40b0ba..0b871ed52a25a4de3fe60e87b77c25a15085420f 100644 (file)
@@ -2709,9 +2709,8 @@ void zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, int d
 }
 /* }}} */
 
-static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node) /* {{{ */
+static void zend_compile_unkeyed_list_assign(zend_ast_list *list, znode *expr_node) /* {{{ */
 {
-       zend_ast_list *list = zend_ast_get_list(ast);
        uint32_t i;
        zend_bool has_elems = 0;
 
@@ -2738,6 +2737,40 @@ static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_n
        if (!has_elems) {
                zend_error_noreturn(E_COMPILE_ERROR, "Cannot use empty list");
        }
+}
+/* }}} */
+
+static void zend_compile_keyed_list_assign(zend_ast_list *list, znode *expr_node) /* {{{ */
+{
+       uint32_t i;
+
+       for (i = 0; i < list->children; ++i) {
+               zend_ast *pair_ast = list->child[i];
+               zend_ast *var_ast = pair_ast->child[0];
+               zend_ast *key_ast = pair_ast->child[1];
+               znode fetch_result, dim_node;
+
+               zend_compile_expr(&dim_node, key_ast);
+
+               if (expr_node->op_type == IS_CONST) {
+                       Z_TRY_ADDREF(expr_node->u.constant);
+               }
+
+               zend_emit_op(&fetch_result, ZEND_FETCH_LIST, expr_node, &dim_node);
+               zend_emit_assign_znode(var_ast, &fetch_result);
+       }
+}
+/* }}} */
+
+static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node) /* {{{ */
+{
+       zend_ast_list *list = zend_ast_get_list(ast);
+
+       if (list->children > 0 && list->child[0] != NULL && list->child[0]->kind == ZEND_AST_ARRAY_ELEM) {
+               zend_compile_keyed_list_assign(list, expr_node);
+       } else {
+               zend_compile_unkeyed_list_assign(list, expr_node);
+       }
 
        *result = *expr_node;
 }
index 754c50215dac5f22e4f5cd709fac97d74d2f8faa..0ec991e9086fa0e5eace79e18c329399b671f785 100644 (file)
@@ -241,7 +241,8 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
 %type <ast> exit_expr scalar backticks_expr lexical_var function_call member_name property_name
 %type <ast> variable_class_name dereferencable_scalar constant dereferencable
 %type <ast> callable_expr callable_variable static_member new_variable
-%type <ast> assignment_list_element array_pair encaps_var encaps_var_offset isset_variables
+%type <ast> unkeyed_assignment_list_element keyed_assignment_list_element array_pair
+%type <ast> encaps_var encaps_var_offset isset_variables
 %type <ast> top_statement_list use_declarations const_list inner_statement_list if_stmt
 %type <ast> alt_if_stmt for_exprs switch_case_list global_var_list static_var_list
 %type <ast> echo_expr_list unset_variables catch_list parameter_list class_statement_list
@@ -250,7 +251,8 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
 %type <ast> class_const_list class_const_decl name_list trait_adaptations method_body non_empty_for_exprs
 %type <ast> ctor_arguments alt_if_stmt_without_else trait_adaptation_list lexical_vars
 %type <ast> lexical_var_list encaps_list array_pair_list non_empty_array_pair_list
-%type <ast> assignment_list isset_variable type return_type
+%type <ast> assignment_list unkeyed_assignment_list keyed_assignment_list
+%type <ast> isset_variable type return_type
 %type <ast> identifier
 
 %type <num> returns_ref function is_reference is_variadic variable_modifiers
@@ -1170,18 +1172,39 @@ property_name:
 ;
 
 assignment_list:
-               assignment_list ',' assignment_list_element
+               unkeyed_assignment_list
+                       { $$ = $1; }
+       |       keyed_assignment_list possible_comma
+                       { $$ = $1; }
+;
+
+unkeyed_assignment_list:
+               unkeyed_assignment_list ',' unkeyed_assignment_list_element
                        { $$ = zend_ast_list_add($1, $3); }
-       |       assignment_list_element
+       |       unkeyed_assignment_list_element
                        { $$ = zend_ast_create_list(1, ZEND_AST_LIST, $1); }
 ;
 
-assignment_list_element:
+unkeyed_assignment_list_element:
                variable                                                { $$ = $1; }
        |       T_LIST '(' assignment_list ')'  { $$ = $3; }
        |       /* empty */                                             { $$ = NULL; }
 ;
 
+keyed_assignment_list:
+               keyed_assignment_list ',' keyed_assignment_list_element
+                       { $$ = zend_ast_list_add($1, $3); }
+       |       keyed_assignment_list_element
+                       { $$ = zend_ast_create_list(1, ZEND_AST_LIST, $1); }
+;
+
+keyed_assignment_list_element:
+               expr T_DOUBLE_ARROW variable
+                       { $$ = zend_ast_create(ZEND_AST_ARRAY_ELEM, $3, $1); }
+       |       expr T_DOUBLE_ARROW T_LIST '(' assignment_list ')'
+                       { $$ = zend_ast_create(ZEND_AST_ARRAY_ELEM, $5, $1); }
+;
+
 
 array_pair_list:
                /* empty */ { $$ = zend_ast_create_list(0, ZEND_AST_ARRAY); }
index af9daa89b1d196bdcac811e6f02324aaac4e2f1d..e2ee420f89e5dd9049a7ae11a0320f75a496c574 100644 (file)
@@ -2062,30 +2062,80 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV)
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
-ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMPVAR|CV, CONST)
+ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
 {
        USE_OPLINE
        zend_free_op free_op1;
+       zend_free_op free_op2;
        zval *container;
+       zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R);
 
        SAVE_OPLINE();
        container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
 
 ZEND_VM_C_LABEL(try_fetch_list):
        if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
-               zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2)));
+               zval *value;
+               zend_string *str;
+               zend_ulong hval;
 
-               if (UNEXPECTED(value == NULL)) {
-                       zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2)));
-                       ZVAL_NULL(EX_VAR(opline->result.var));
+ZEND_VM_C_LABEL(assign_again_list):
+               if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+                       hval = Z_LVAL_P(offset);
+ZEND_VM_C_LABEL(num_index_list):
+                       value = zend_hash_index_find(Z_ARRVAL_P(container), hval);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval);
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
+                       str = Z_STR_P(offset);
+
+                       if (ZEND_HANDLE_NUMERIC(str, hval)) {
+                               ZEND_VM_C_GOTO(num_index_list);
+                       }
+
+ZEND_VM_C_LABEL(str_index_list):
+                       value = zend_hash_find(Z_ARRVAL_P(container), str);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str));
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+                       if (UNEXPECTED(str != Z_STR_P(offset))) {
+                               zend_string_release(str);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
+                       offset = Z_REFVAL_P(offset);
+                       ZEND_VM_C_GOTO(assign_again_list);
+               } else if (Z_TYPE_P(offset) == IS_NULL) {
+                       str = ZSTR_EMPTY_ALLOC();
+                       ZEND_VM_C_GOTO(str_index_list);
+               } else if (Z_TYPE_P(offset) == IS_DOUBLE) {
+                       hval = zend_dval_to_lval(Z_DVAL_P(offset));
+                       ZEND_VM_C_GOTO(num_index_list);
+               } else if (Z_TYPE_P(offset) == IS_FALSE) {
+                       hval = 0;
+                       ZEND_VM_C_GOTO(num_index_list);
+               } else if (Z_TYPE_P(offset) == IS_TRUE) {
+                       hval = 1;
+                       ZEND_VM_C_GOTO(num_index_list);
+               } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+                       zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+                       hval = Z_RES_HANDLE_P(offset);
                } else {
-                       ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       zend_error(E_WARNING, "Illegal offset type");
                }
        } else if (OP1_TYPE != IS_CONST &&
                   UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
                   EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
                zval *result = EX_VAR(opline->result.var);
-               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, EX_CONSTANT(opline->op2), BP_VAR_R, result);
+               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result);
 
                if (retval) {
                        if (result != retval) {
@@ -2103,6 +2153,7 @@ ZEND_VM_C_LABEL(try_fetch_list):
                }
                ZVAL_NULL(EX_VAR(opline->result.var));
        }
+       FREE_OP2();
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
index a4edfd0f98e89e0c1466910da7d6aed3fe2fb10c..612feb9e9c8f9ceddaf567957254a16c28267370 100644 (file)
@@ -5746,26 +5746,76 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_CONST_HA
 {
        USE_OPLINE
 
+
        zval *container;
+       zval *offset = EX_CONSTANT(opline->op2);
 
        SAVE_OPLINE();
        container = EX_CONSTANT(opline->op1);
 
 try_fetch_list:
        if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
-               zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2)));
+               zval *value;
+               zend_string *str;
+               zend_ulong hval;
 
-               if (UNEXPECTED(value == NULL)) {
-                       zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2)));
-                       ZVAL_NULL(EX_VAR(opline->result.var));
+assign_again_list:
+               if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+                       hval = Z_LVAL_P(offset);
+num_index_list:
+                       value = zend_hash_index_find(Z_ARRVAL_P(container), hval);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval);
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
+                       str = Z_STR_P(offset);
+
+                       if (ZEND_HANDLE_NUMERIC(str, hval)) {
+                               goto num_index_list;
+                       }
+
+str_index_list:
+                       value = zend_hash_find(Z_ARRVAL_P(container), str);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str));
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+                       if (UNEXPECTED(str != Z_STR_P(offset))) {
+                               zend_string_release(str);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
+                       offset = Z_REFVAL_P(offset);
+                       goto assign_again_list;
+               } else if (Z_TYPE_P(offset) == IS_NULL) {
+                       str = ZSTR_EMPTY_ALLOC();
+                       goto str_index_list;
+               } else if (Z_TYPE_P(offset) == IS_DOUBLE) {
+                       hval = zend_dval_to_lval(Z_DVAL_P(offset));
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_FALSE) {
+                       hval = 0;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_TRUE) {
+                       hval = 1;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+                       zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+                       hval = Z_RES_HANDLE_P(offset);
                } else {
-                       ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       zend_error(E_WARNING, "Illegal offset type");
                }
        } else if (IS_CONST != IS_CONST &&
                   UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
                   EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
                zval *result = EX_VAR(opline->result.var);
-               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, EX_CONSTANT(opline->op2), BP_VAR_R, result);
+               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result);
 
                if (retval) {
                        if (result != retval) {
@@ -5783,6 +5833,7 @@ try_fetch_list:
                }
                ZVAL_NULL(EX_VAR(opline->result.var));
        }
+
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
@@ -9499,6 +9550,101 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_
        }
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+
+
+       zval *container;
+       zval *offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+
+       SAVE_OPLINE();
+       container = EX_CONSTANT(opline->op1);
+
+try_fetch_list:
+       if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+               zval *value;
+               zend_string *str;
+               zend_ulong hval;
+
+assign_again_list:
+               if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+                       hval = Z_LVAL_P(offset);
+num_index_list:
+                       value = zend_hash_index_find(Z_ARRVAL_P(container), hval);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval);
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
+                       str = Z_STR_P(offset);
+
+                       if (ZEND_HANDLE_NUMERIC(str, hval)) {
+                               goto num_index_list;
+                       }
+
+str_index_list:
+                       value = zend_hash_find(Z_ARRVAL_P(container), str);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str));
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+                       if (UNEXPECTED(str != Z_STR_P(offset))) {
+                               zend_string_release(str);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
+                       offset = Z_REFVAL_P(offset);
+                       goto assign_again_list;
+               } else if (Z_TYPE_P(offset) == IS_NULL) {
+                       str = ZSTR_EMPTY_ALLOC();
+                       goto str_index_list;
+               } else if (Z_TYPE_P(offset) == IS_DOUBLE) {
+                       hval = zend_dval_to_lval(Z_DVAL_P(offset));
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_FALSE) {
+                       hval = 0;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_TRUE) {
+                       hval = 1;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+                       zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+                       hval = Z_RES_HANDLE_P(offset);
+               } else {
+                       zend_error(E_WARNING, "Illegal offset type");
+               }
+       } else if (IS_CONST != IS_CONST &&
+                  UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
+                  EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
+               zval *result = EX_VAR(opline->result.var);
+               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result);
+
+               if (retval) {
+                       if (result != retval) {
+                               ZVAL_COPY(result, retval);
+                       }
+               } else {
+                       ZVAL_NULL(result);
+               }
+       } else if ((IS_CONST & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) {
+               container = Z_REFVAL_P(container);
+               goto try_fetch_list;
+       } else {
+               if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
+                       GET_OP1_UNDEF_CV(container, BP_VAR_R);
+               }
+               ZVAL_NULL(EX_VAR(opline->result.var));
+       }
+
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -11310,6 +11456,101 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_
        }
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+
+       zend_free_op free_op2;
+       zval *container;
+       zval *offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+
+       SAVE_OPLINE();
+       container = EX_CONSTANT(opline->op1);
+
+try_fetch_list:
+       if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+               zval *value;
+               zend_string *str;
+               zend_ulong hval;
+
+assign_again_list:
+               if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+                       hval = Z_LVAL_P(offset);
+num_index_list:
+                       value = zend_hash_index_find(Z_ARRVAL_P(container), hval);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval);
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
+                       str = Z_STR_P(offset);
+
+                       if (ZEND_HANDLE_NUMERIC(str, hval)) {
+                               goto num_index_list;
+                       }
+
+str_index_list:
+                       value = zend_hash_find(Z_ARRVAL_P(container), str);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str));
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+                       if (UNEXPECTED(str != Z_STR_P(offset))) {
+                               zend_string_release(str);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
+                       offset = Z_REFVAL_P(offset);
+                       goto assign_again_list;
+               } else if (Z_TYPE_P(offset) == IS_NULL) {
+                       str = ZSTR_EMPTY_ALLOC();
+                       goto str_index_list;
+               } else if (Z_TYPE_P(offset) == IS_DOUBLE) {
+                       hval = zend_dval_to_lval(Z_DVAL_P(offset));
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_FALSE) {
+                       hval = 0;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_TRUE) {
+                       hval = 1;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+                       zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+                       hval = Z_RES_HANDLE_P(offset);
+               } else {
+                       zend_error(E_WARNING, "Illegal offset type");
+               }
+       } else if (IS_CONST != IS_CONST &&
+                  UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
+                  EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
+               zval *result = EX_VAR(opline->result.var);
+               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result);
+
+               if (retval) {
+                       if (result != retval) {
+                               ZVAL_COPY(result, retval);
+                       }
+               } else {
+                       ZVAL_NULL(result);
+               }
+       } else if ((IS_CONST & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) {
+               container = Z_REFVAL_P(container);
+               goto try_fetch_list;
+       } else {
+               if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
+                       GET_OP1_UNDEF_CV(container, BP_VAR_R);
+               }
+               ZVAL_NULL(EX_VAR(opline->result.var));
+       }
+       zval_ptr_dtor_nogc(free_op2);
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -37859,26 +38100,76 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_CONST_HANDL
 {
        USE_OPLINE
 
+
        zval *container;
+       zval *offset = EX_CONSTANT(opline->op2);
 
        SAVE_OPLINE();
        container = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);
 
 try_fetch_list:
        if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
-               zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2)));
+               zval *value;
+               zend_string *str;
+               zend_ulong hval;
 
-               if (UNEXPECTED(value == NULL)) {
-                       zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2)));
-                       ZVAL_NULL(EX_VAR(opline->result.var));
+assign_again_list:
+               if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+                       hval = Z_LVAL_P(offset);
+num_index_list:
+                       value = zend_hash_index_find(Z_ARRVAL_P(container), hval);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval);
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
+                       str = Z_STR_P(offset);
+
+                       if (ZEND_HANDLE_NUMERIC(str, hval)) {
+                               goto num_index_list;
+                       }
+
+str_index_list:
+                       value = zend_hash_find(Z_ARRVAL_P(container), str);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str));
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+                       if (UNEXPECTED(str != Z_STR_P(offset))) {
+                               zend_string_release(str);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
+                       offset = Z_REFVAL_P(offset);
+                       goto assign_again_list;
+               } else if (Z_TYPE_P(offset) == IS_NULL) {
+                       str = ZSTR_EMPTY_ALLOC();
+                       goto str_index_list;
+               } else if (Z_TYPE_P(offset) == IS_DOUBLE) {
+                       hval = zend_dval_to_lval(Z_DVAL_P(offset));
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_FALSE) {
+                       hval = 0;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_TRUE) {
+                       hval = 1;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+                       zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+                       hval = Z_RES_HANDLE_P(offset);
                } else {
-                       ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       zend_error(E_WARNING, "Illegal offset type");
                }
        } else if (IS_CV != IS_CONST &&
                   UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
                   EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
                zval *result = EX_VAR(opline->result.var);
-               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, EX_CONSTANT(opline->op2), BP_VAR_R, result);
+               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result);
 
                if (retval) {
                        if (result != retval) {
@@ -37896,6 +38187,7 @@ try_fetch_list:
                }
                ZVAL_NULL(EX_VAR(opline->result.var));
        }
+
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
@@ -44238,6 +44530,101 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_CV_HAN
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+
+
+       zval *container;
+       zval *offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+
+       SAVE_OPLINE();
+       container = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);
+
+try_fetch_list:
+       if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+               zval *value;
+               zend_string *str;
+               zend_ulong hval;
+
+assign_again_list:
+               if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+                       hval = Z_LVAL_P(offset);
+num_index_list:
+                       value = zend_hash_index_find(Z_ARRVAL_P(container), hval);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval);
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
+                       str = Z_STR_P(offset);
+
+                       if (ZEND_HANDLE_NUMERIC(str, hval)) {
+                               goto num_index_list;
+                       }
+
+str_index_list:
+                       value = zend_hash_find(Z_ARRVAL_P(container), str);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str));
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+                       if (UNEXPECTED(str != Z_STR_P(offset))) {
+                               zend_string_release(str);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
+                       offset = Z_REFVAL_P(offset);
+                       goto assign_again_list;
+               } else if (Z_TYPE_P(offset) == IS_NULL) {
+                       str = ZSTR_EMPTY_ALLOC();
+                       goto str_index_list;
+               } else if (Z_TYPE_P(offset) == IS_DOUBLE) {
+                       hval = zend_dval_to_lval(Z_DVAL_P(offset));
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_FALSE) {
+                       hval = 0;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_TRUE) {
+                       hval = 1;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+                       zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+                       hval = Z_RES_HANDLE_P(offset);
+               } else {
+                       zend_error(E_WARNING, "Illegal offset type");
+               }
+       } else if (IS_CV != IS_CONST &&
+                  UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
+                  EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
+               zval *result = EX_VAR(opline->result.var);
+               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result);
+
+               if (retval) {
+                       if (result != retval) {
+                               ZVAL_COPY(result, retval);
+                       }
+               } else {
+                       ZVAL_NULL(result);
+               }
+       } else if ((IS_CV & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) {
+               container = Z_REFVAL_P(container);
+               goto try_fetch_list;
+       } else {
+               if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
+                       GET_OP1_UNDEF_CV(container, BP_VAR_R);
+               }
+               ZVAL_NULL(EX_VAR(opline->result.var));
+       }
+
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -47793,6 +48180,101 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_TMPVAR
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+
+       zend_free_op free_op2;
+       zval *container;
+       zval *offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+
+       SAVE_OPLINE();
+       container = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);
+
+try_fetch_list:
+       if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+               zval *value;
+               zend_string *str;
+               zend_ulong hval;
+
+assign_again_list:
+               if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+                       hval = Z_LVAL_P(offset);
+num_index_list:
+                       value = zend_hash_index_find(Z_ARRVAL_P(container), hval);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval);
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
+                       str = Z_STR_P(offset);
+
+                       if (ZEND_HANDLE_NUMERIC(str, hval)) {
+                               goto num_index_list;
+                       }
+
+str_index_list:
+                       value = zend_hash_find(Z_ARRVAL_P(container), str);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str));
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+                       if (UNEXPECTED(str != Z_STR_P(offset))) {
+                               zend_string_release(str);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
+                       offset = Z_REFVAL_P(offset);
+                       goto assign_again_list;
+               } else if (Z_TYPE_P(offset) == IS_NULL) {
+                       str = ZSTR_EMPTY_ALLOC();
+                       goto str_index_list;
+               } else if (Z_TYPE_P(offset) == IS_DOUBLE) {
+                       hval = zend_dval_to_lval(Z_DVAL_P(offset));
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_FALSE) {
+                       hval = 0;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_TRUE) {
+                       hval = 1;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+                       zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+                       hval = Z_RES_HANDLE_P(offset);
+               } else {
+                       zend_error(E_WARNING, "Illegal offset type");
+               }
+       } else if (IS_CV != IS_CONST &&
+                  UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
+                  EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
+               zval *result = EX_VAR(opline->result.var);
+               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result);
+
+               if (retval) {
+                       if (result != retval) {
+                               ZVAL_COPY(result, retval);
+                       }
+               } else {
+                       ZVAL_NULL(result);
+               }
+       } else if ((IS_CV & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) {
+               container = Z_REFVAL_P(container);
+               goto try_fetch_list;
+       } else {
+               if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
+                       GET_OP1_UNDEF_CV(container, BP_VAR_R);
+               }
+               ZVAL_NULL(EX_VAR(opline->result.var));
+       }
+       zval_ptr_dtor_nogc(free_op2);
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -51010,26 +51492,76 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_H
 {
        USE_OPLINE
        zend_free_op free_op1;
+
        zval *container;
+       zval *offset = EX_CONSTANT(opline->op2);
 
        SAVE_OPLINE();
        container = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
 
 try_fetch_list:
        if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
-               zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2)));
+               zval *value;
+               zend_string *str;
+               zend_ulong hval;
 
-               if (UNEXPECTED(value == NULL)) {
-                       zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2)));
-                       ZVAL_NULL(EX_VAR(opline->result.var));
+assign_again_list:
+               if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+                       hval = Z_LVAL_P(offset);
+num_index_list:
+                       value = zend_hash_index_find(Z_ARRVAL_P(container), hval);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval);
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
+                       str = Z_STR_P(offset);
+
+                       if (ZEND_HANDLE_NUMERIC(str, hval)) {
+                               goto num_index_list;
+                       }
+
+str_index_list:
+                       value = zend_hash_find(Z_ARRVAL_P(container), str);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str));
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+                       if (UNEXPECTED(str != Z_STR_P(offset))) {
+                               zend_string_release(str);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
+                       offset = Z_REFVAL_P(offset);
+                       goto assign_again_list;
+               } else if (Z_TYPE_P(offset) == IS_NULL) {
+                       str = ZSTR_EMPTY_ALLOC();
+                       goto str_index_list;
+               } else if (Z_TYPE_P(offset) == IS_DOUBLE) {
+                       hval = zend_dval_to_lval(Z_DVAL_P(offset));
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_FALSE) {
+                       hval = 0;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_TRUE) {
+                       hval = 1;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+                       zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+                       hval = Z_RES_HANDLE_P(offset);
                } else {
-                       ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       zend_error(E_WARNING, "Illegal offset type");
                }
        } else if ((IS_TMP_VAR|IS_VAR) != IS_CONST &&
                   UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
                   EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
                zval *result = EX_VAR(opline->result.var);
-               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, EX_CONSTANT(opline->op2), BP_VAR_R, result);
+               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result);
 
                if (retval) {
                        if (result != retval) {
@@ -51047,6 +51579,7 @@ try_fetch_list:
                }
                ZVAL_NULL(EX_VAR(opline->result.var));
        }
+
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
@@ -53295,6 +53828,101 @@ fetch_obj_is_no_object:
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+       zend_free_op free_op1;
+
+       zval *container;
+       zval *offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+
+       SAVE_OPLINE();
+       container = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
+
+try_fetch_list:
+       if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+               zval *value;
+               zend_string *str;
+               zend_ulong hval;
+
+assign_again_list:
+               if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+                       hval = Z_LVAL_P(offset);
+num_index_list:
+                       value = zend_hash_index_find(Z_ARRVAL_P(container), hval);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval);
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
+                       str = Z_STR_P(offset);
+
+                       if (ZEND_HANDLE_NUMERIC(str, hval)) {
+                               goto num_index_list;
+                       }
+
+str_index_list:
+                       value = zend_hash_find(Z_ARRVAL_P(container), str);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str));
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+                       if (UNEXPECTED(str != Z_STR_P(offset))) {
+                               zend_string_release(str);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
+                       offset = Z_REFVAL_P(offset);
+                       goto assign_again_list;
+               } else if (Z_TYPE_P(offset) == IS_NULL) {
+                       str = ZSTR_EMPTY_ALLOC();
+                       goto str_index_list;
+               } else if (Z_TYPE_P(offset) == IS_DOUBLE) {
+                       hval = zend_dval_to_lval(Z_DVAL_P(offset));
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_FALSE) {
+                       hval = 0;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_TRUE) {
+                       hval = 1;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+                       zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+                       hval = Z_RES_HANDLE_P(offset);
+               } else {
+                       zend_error(E_WARNING, "Illegal offset type");
+               }
+       } else if ((IS_TMP_VAR|IS_VAR) != IS_CONST &&
+                  UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
+                  EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
+               zval *result = EX_VAR(opline->result.var);
+               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result);
+
+               if (retval) {
+                       if (result != retval) {
+                               ZVAL_COPY(result, retval);
+                       }
+               } else {
+                       ZVAL_NULL(result);
+               }
+       } else if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) {
+               container = Z_REFVAL_P(container);
+               goto try_fetch_list;
+       } else {
+               if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
+                       GET_OP1_UNDEF_CV(container, BP_VAR_R);
+               }
+               ZVAL_NULL(EX_VAR(opline->result.var));
+       }
+
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -54444,6 +55072,101 @@ fetch_obj_is_no_object:
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+       zend_free_op free_op1;
+       zend_free_op free_op2;
+       zval *container;
+       zval *offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+
+       SAVE_OPLINE();
+       container = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
+
+try_fetch_list:
+       if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+               zval *value;
+               zend_string *str;
+               zend_ulong hval;
+
+assign_again_list:
+               if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+                       hval = Z_LVAL_P(offset);
+num_index_list:
+                       value = zend_hash_index_find(Z_ARRVAL_P(container), hval);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval);
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
+                       str = Z_STR_P(offset);
+
+                       if (ZEND_HANDLE_NUMERIC(str, hval)) {
+                               goto num_index_list;
+                       }
+
+str_index_list:
+                       value = zend_hash_find(Z_ARRVAL_P(container), str);
+
+                       if (UNEXPECTED(value == NULL)) {
+                               zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str));
+                               ZVAL_NULL(EX_VAR(opline->result.var));
+                       } else {
+                               ZVAL_COPY(EX_VAR(opline->result.var), value);
+                       }
+                       if (UNEXPECTED(str != Z_STR_P(offset))) {
+                               zend_string_release(str);
+                       }
+               } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
+                       offset = Z_REFVAL_P(offset);
+                       goto assign_again_list;
+               } else if (Z_TYPE_P(offset) == IS_NULL) {
+                       str = ZSTR_EMPTY_ALLOC();
+                       goto str_index_list;
+               } else if (Z_TYPE_P(offset) == IS_DOUBLE) {
+                       hval = zend_dval_to_lval(Z_DVAL_P(offset));
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_FALSE) {
+                       hval = 0;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_TRUE) {
+                       hval = 1;
+                       goto num_index_list;
+               } else if (Z_TYPE_P(offset) == IS_RESOURCE) {
+                       zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+                       hval = Z_RES_HANDLE_P(offset);
+               } else {
+                       zend_error(E_WARNING, "Illegal offset type");
+               }
+       } else if ((IS_TMP_VAR|IS_VAR) != IS_CONST &&
+                  UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
+                  EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
+               zval *result = EX_VAR(opline->result.var);
+               zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result);
+
+               if (retval) {
+                       if (result != retval) {
+                               ZVAL_COPY(result, retval);
+                       }
+               } else {
+                       ZVAL_NULL(result);
+               }
+       } else if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) {
+               container = Z_REFVAL_P(container);
+               goto try_fetch_list;
+       } else {
+               if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
+                       GET_OP1_UNDEF_CV(container, BP_VAR_R);
+               }
+               ZVAL_NULL(EX_VAR(opline->result.var));
+       }
+       zval_ptr_dtor_nogc(free_op2);
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -57495,30 +58218,30 @@ void zend_init_opcodes_handlers(void)
                ZEND_NULL_HANDLER,
                ZEND_FETCH_OBJ_UNSET_SPEC_CV_CV_HANDLER,
                ZEND_FETCH_LIST_SPEC_CONST_CONST_HANDLER,
+               ZEND_FETCH_LIST_SPEC_CONST_TMPVAR_HANDLER,
+               ZEND_FETCH_LIST_SPEC_CONST_TMPVAR_HANDLER,
                ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
+               ZEND_FETCH_LIST_SPEC_CONST_CV_HANDLER,
                ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_HANDLER,
+               ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER,
+               ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER,
                ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
+               ZEND_FETCH_LIST_SPEC_TMPVAR_CV_HANDLER,
                ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_HANDLER,
+               ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER,
+               ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER,
                ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
+               ZEND_FETCH_LIST_SPEC_TMPVAR_CV_HANDLER,
                ZEND_NULL_HANDLER,
                ZEND_NULL_HANDLER,
                ZEND_NULL_HANDLER,
                ZEND_NULL_HANDLER,
                ZEND_NULL_HANDLER,
                ZEND_FETCH_LIST_SPEC_CV_CONST_HANDLER,
+               ZEND_FETCH_LIST_SPEC_CV_TMPVAR_HANDLER,
+               ZEND_FETCH_LIST_SPEC_CV_TMPVAR_HANDLER,
                ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
+               ZEND_FETCH_LIST_SPEC_CV_CV_HANDLER,
                ZEND_NULL_HANDLER,
                ZEND_NULL_HANDLER,
                ZEND_NULL_HANDLER,
index 37ba8d411ba34443c84042198fa0165246c87847..ac5f0d6a32eeee981982ac59ba1b2660a72cde8b 100644 (file)
@@ -307,7 +307,7 @@ static uint32_t zend_vm_opcodes_flags[184] = {
        0x00010107,
        0x00000701,
        0x00000751,
-       0x00000307,
+       0x00000707,
        0x06000301,
        0x00000000,
        0x00000000,