Skip to content

Commit 6d4de4c

Browse files
David Walkernikic
authored andcommitted
Implement list() reference assignments
Support list() reference assignments of the form: list(&$a, list(&$b, $c)) = $d; RFC: https://wiki.php.net/rfc/list_reference_assignment
1 parent 261ddb7 commit 6d4de4c

26 files changed

+1033
-171
lines changed

‎NEWS‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ PHP NEWS
99
. Removed support for BeOS. (Kalle)
1010
. Add PHP_VERSION to phpinfo() <title/>. (github/MattJeevas)
1111
. Add net_get_interfaces(). (Sara, Joe, Anatol)
12+
. Added support for references in list() and array destructuring, per
13+
RFC https://wiki.php.net/rfc/list_reference_assignment.
14+
(David Walker)
1215
. Fixed bug #75031 (support append mode in temp/memory streams). (adsr)
1316
. Fixed bug #74860 (Uncaught exceptions not being formatted properly when
1417
error_log set to "syslog"). (Philip Prindeville)

‎UPGRADING‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ Standard:
4545
2. New Features
4646
========================================
4747

48+
Core:
49+
. Array destructuring now supports reference assignments using the syntax
50+
[&$a, [$b, &$c]] = $d. The same is also supported for list().
51+
(RFC: https://wiki.php.net/rfc/list_reference_assignment)
52+
4853
BCMath:
4954
. bcscale() can now also be used as getter to retrieve the current scale in use.
5055

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
--TEST--
2+
"Reference Unpacking - General" list()
3+
--FILE--
4+
<?php
5+
$arr = array(1, array(2));
6+
list(&$a, list(&$b)) = $arr;
7+
var_dump($a, $b);
8+
var_dump($arr);
9+
10+
$arr = array(1, array(2));
11+
list($a, &$b) = $arr;
12+
var_dump($arr);
13+
14+
$arr = array(1, array(2));
15+
[&$a, [&$b]] = $arr;
16+
var_dump($a, $b);
17+
var_dump($arr);
18+
19+
$arr = array(1, array(2));
20+
[&$a, [&$b], &$c] = $arr;
21+
var_dump($a, $b, $c);
22+
var_dump($arr);
23+
24+
$arr = array("one" => 1, "two" => array(2));
25+
["one" => &$a, "two" => [&$b], "three" => &$c] = $arr;
26+
var_dump($a, $b, $c);
27+
var_dump($arr);
28+
?>
29+
--EXPECTF--
30+
int(1)
31+
int(2)
32+
array(2) {
33+
[0]=>
34+
&int(1)
35+
[1]=>
36+
array(1) {
37+
[0]=>
38+
&int(2)
39+
}
40+
}
41+
array(2) {
42+
[0]=>
43+
int(1)
44+
[1]=>
45+
&array(1) {
46+
[0]=>
47+
int(2)
48+
}
49+
}
50+
int(1)
51+
int(2)
52+
array(2) {
53+
[0]=>
54+
&int(1)
55+
[1]=>
56+
array(1) {
57+
[0]=>
58+
&int(2)
59+
}
60+
}
61+
int(1)
62+
int(2)
63+
NULL
64+
array(3) {
65+
[0]=>
66+
&int(1)
67+
[1]=>
68+
array(1) {
69+
[0]=>
70+
&int(2)
71+
}
72+
[2]=>
73+
&NULL
74+
}
75+
int(1)
76+
int(2)
77+
NULL
78+
array(3) {
79+
["one"]=>
80+
&int(1)
81+
["two"]=>
82+
array(1) {
83+
[0]=>
84+
&int(2)
85+
}
86+
["three"]=>
87+
&NULL
88+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
"Reference Unpacking - New Reference" list()
3+
--FILE--
4+
<?php
5+
$arr = array(new stdclass);
6+
list(&$a, &$b) = $arr;
7+
var_dump($a, $b);
8+
var_dump($arr);
9+
?>
10+
--EXPECTF--
11+
object(stdClass)#%d (0) {
12+
}
13+
NULL
14+
array(2) {
15+
[0]=>
16+
&object(stdClass)#%d (0) {
17+
}
18+
[1]=>
19+
&NULL
20+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
--TEST--
2+
"Reference Unpacking - From Functions" list()
3+
--FILE--
4+
<?php
5+
$arr = [1, 2];
6+
function no_ref($a) {
7+
return $a;
8+
}
9+
10+
function no_ref_by_ref(&$a) {
11+
return $a;
12+
}
13+
14+
function &ref_return(&$a) {
15+
return $a;
16+
}
17+
18+
function &ref_return_global() {
19+
global $arr;
20+
return $arr;
21+
}
22+
23+
$a = [1, 2];
24+
[&$var] = no_ref($a);
25+
var_dump($var);
26+
var_dump($a);
27+
28+
$a = [1, 2];
29+
[&$var] = no_ref_by_ref($a);
30+
var_dump($var);
31+
var_dump($a);
32+
33+
$a = [1, 2];
34+
[&$var] = ref_return($a);
35+
var_dump($var);
36+
var_dump($a);
37+
38+
[,&$var] = ref_return_global();
39+
var_dump($var);
40+
var_dump($arr);
41+
?>
42+
--EXPECTF--
43+
Notice: Attempting to set reference to non referenceable value in %s on line %d
44+
int(1)
45+
array(2) {
46+
[0]=>
47+
int(1)
48+
[1]=>
49+
int(2)
50+
}
51+
52+
Notice: Attempting to set reference to non referenceable value in %s on line %d
53+
int(1)
54+
array(2) {
55+
[0]=>
56+
int(1)
57+
[1]=>
58+
int(2)
59+
}
60+
int(1)
61+
array(2) {
62+
[0]=>
63+
&int(1)
64+
[1]=>
65+
int(2)
66+
}
67+
int(2)
68+
array(2) {
69+
[0]=>
70+
int(1)
71+
[1]=>
72+
&int(2)
73+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
"Reference Unpacking - Foreach" list()
3+
--FILE--
4+
<?php
5+
$coords = array(array(1, 2), array(3, 4));
6+
foreach ($coords as [&$x, $y]) {
7+
$x++;
8+
$y++;
9+
}
10+
var_dump($coords);
11+
?>
12+
--EXPECTF--
13+
array(2) {
14+
[0]=>
15+
array(2) {
16+
[0]=>
17+
int(2)
18+
[1]=>
19+
int(2)
20+
}
21+
[1]=>
22+
array(2) {
23+
[0]=>
24+
&int(4)
25+
[1]=>
26+
int(4)
27+
}
28+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
--TEST--
2+
"Reference Unpacking - Class Property and Methods" list()
3+
--FILE--
4+
<?php
5+
class A {
6+
public $a = [['hello']];
7+
public $b = ['world'];
8+
9+
public function getVar() {
10+
return $this->a;
11+
}
12+
13+
public function &getVarRef() {
14+
return $this->a;
15+
}
16+
}
17+
18+
class B {
19+
static $a = [['world']];
20+
}
21+
22+
$a = new A();
23+
[&$var] = $a->a;
24+
[&$var_too] = $a->b;
25+
var_dump($a->a);
26+
var_dump($a->b);
27+
28+
$a = new A();
29+
[&$var] = $a->getVar();
30+
var_dump($a->a);
31+
32+
$a = new A();
33+
[&$var] = $a->getVarRef();
34+
var_dump($a->a);
35+
36+
[&$var] = B::$a;
37+
var_dump(B::$a);
38+
?>
39+
--EXPECTF--
40+
array(1) {
41+
[0]=>
42+
&array(1) {
43+
[0]=>
44+
string(5) "hello"
45+
}
46+
}
47+
array(1) {
48+
[0]=>
49+
&string(5) "world"
50+
}
51+
52+
Notice: Attempting to set reference to non referenceable value in %s on line %d
53+
array(1) {
54+
[0]=>
55+
array(1) {
56+
[0]=>
57+
string(5) "hello"
58+
}
59+
}
60+
array(1) {
61+
[0]=>
62+
&array(1) {
63+
[0]=>
64+
string(5) "hello"
65+
}
66+
}
67+
array(1) {
68+
[0]=>
69+
&array(1) {
70+
[0]=>
71+
string(5) "world"
72+
}
73+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
"Reference Unpacking - Class ArrayAccess No Reference" list()
3+
--FILE--
4+
<?php
5+
class StorageNoRef implements ArrayAccess {
6+
private $s = [];
7+
function __construct(array $a) { $this->s = $a; }
8+
function offsetSet ($k, $v) { $this->s[$k] = $v; }
9+
function offsetGet ($k) { return $this->s[$k]; }
10+
function offsetExists ($k) { return isset($this->s[$k]); }
11+
function offsetUnset ($k) { unset($this->s[$k]); }
12+
}
13+
14+
$a = new StorageNoRef([1, 2]);
15+
list(&$one, $two) = $a;
16+
var_dump($a);
17+
18+
$a = new StorageNoRef([1, 2]);
19+
list(,,list($var)) = $a;
20+
var_dump($a);
21+
22+
$a = new StorageNoRef(['one' => 1, 'two' => 2]);
23+
['one' => &$one, 'two' => $two] = $a;
24+
var_dump($a);
25+
?>
26+
--EXPECTF--
27+
Notice: Indirect modification of overloaded element of %s has no effect in %s on line %d
28+
object(StorageNoRef)#1 (1) {
29+
["s":"StorageNoRef":private]=>
30+
array(2) {
31+
[0]=>
32+
int(1)
33+
[1]=>
34+
int(2)
35+
}
36+
}
37+
38+
Notice: Undefined offset: 2 in %s on line %d
39+
object(StorageNoRef)#2 (1) {
40+
["s":"StorageNoRef":private]=>
41+
array(2) {
42+
[0]=>
43+
int(1)
44+
[1]=>
45+
int(2)
46+
}
47+
}
48+
49+
Notice: Indirect modification of overloaded element of %s has no effect in %s on line %d
50+
object(StorageNoRef)#1 (1) {
51+
["s":"StorageNoRef":private]=>
52+
array(2) {
53+
["one"]=>
54+
int(1)
55+
["two"]=>
56+
int(2)
57+
}
58+
}

0 commit comments

Comments
 (0)