Skip to content

Commit

Permalink
Implement list() reference assignments
Browse files Browse the repository at this point in the history
Support list() reference assignments of the form:

    list(&$a, list(&$b, $c)) = $d;

RFC: https://wiki.php.net/rfc/list_reference_assignment
  • Loading branch information
David Walker authored and nikic committed Dec 9, 2017
1 parent 261ddb7 commit 6d4de4c
Show file tree
Hide file tree
Showing 26 changed files with 1,033 additions and 171 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ PHP NEWS
. Removed support for BeOS. (Kalle)
. Add PHP_VERSION to phpinfo() <title/>. (github/MattJeevas)
. Add net_get_interfaces(). (Sara, Joe, Anatol)
. Added support for references in list() and array destructuring, per
RFC https://wiki.php.net/rfc/list_reference_assignment.
(David Walker)
. Fixed bug #75031 (support append mode in temp/memory streams). (adsr)
. Fixed bug #74860 (Uncaught exceptions not being formatted properly when
error_log set to "syslog"). (Philip Prindeville)
Expand Down
5 changes: 5 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ Standard:
2. New Features
========================================

Core:
. Array destructuring now supports reference assignments using the syntax
[&$a, [$b, &$c]] = $d. The same is also supported for list().
(RFC: https://wiki.php.net/rfc/list_reference_assignment)

BCMath:
. bcscale() can now also be used as getter to retrieve the current scale in use.

Expand Down
88 changes: 88 additions & 0 deletions Zend/tests/list/list_reference_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
--TEST--
"Reference Unpacking - General" list()
--FILE--
<?php
$arr = array(1, array(2));
list(&$a, list(&$b)) = $arr;
var_dump($a, $b);
var_dump($arr);

$arr = array(1, array(2));
list($a, &$b) = $arr;
var_dump($arr);

$arr = array(1, array(2));
[&$a, [&$b]] = $arr;
var_dump($a, $b);
var_dump($arr);

$arr = array(1, array(2));
[&$a, [&$b], &$c] = $arr;
var_dump($a, $b, $c);
var_dump($arr);

$arr = array("one" => 1, "two" => array(2));
["one" => &$a, "two" => [&$b], "three" => &$c] = $arr;
var_dump($a, $b, $c);
var_dump($arr);
?>
--EXPECTF--
int(1)
int(2)
array(2) {
[0]=>
&int(1)
[1]=>
array(1) {
[0]=>
&int(2)
}
}
array(2) {
[0]=>
int(1)
[1]=>
&array(1) {
[0]=>
int(2)
}
}
int(1)
int(2)
array(2) {
[0]=>
&int(1)
[1]=>
array(1) {
[0]=>
&int(2)
}
}
int(1)
int(2)
NULL
array(3) {
[0]=>
&int(1)
[1]=>
array(1) {
[0]=>
&int(2)
}
[2]=>
&NULL
}
int(1)
int(2)
NULL
array(3) {
["one"]=>
&int(1)
["two"]=>
array(1) {
[0]=>
&int(2)
}
["three"]=>
&NULL
}
20 changes: 20 additions & 0 deletions Zend/tests/list/list_reference_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
"Reference Unpacking - New Reference" list()
--FILE--
<?php
$arr = array(new stdclass);
list(&$a, &$b) = $arr;
var_dump($a, $b);
var_dump($arr);
?>
--EXPECTF--
object(stdClass)#%d (0) {
}
NULL
array(2) {
[0]=>
&object(stdClass)#%d (0) {
}
[1]=>
&NULL
}
73 changes: 73 additions & 0 deletions Zend/tests/list/list_reference_003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
--TEST--
"Reference Unpacking - From Functions" list()
--FILE--
<?php
$arr = [1, 2];
function no_ref($a) {
return $a;
}

function no_ref_by_ref(&$a) {
return $a;
}

function &ref_return(&$a) {
return $a;
}

function &ref_return_global() {
global $arr;
return $arr;
}

$a = [1, 2];
[&$var] = no_ref($a);
var_dump($var);
var_dump($a);

$a = [1, 2];
[&$var] = no_ref_by_ref($a);
var_dump($var);
var_dump($a);

$a = [1, 2];
[&$var] = ref_return($a);
var_dump($var);
var_dump($a);

[,&$var] = ref_return_global();
var_dump($var);
var_dump($arr);
?>
--EXPECTF--
Notice: Attempting to set reference to non referenceable value in %s on line %d
int(1)
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}

Notice: Attempting to set reference to non referenceable value in %s on line %d
int(1)
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
int(1)
array(2) {
[0]=>
&int(1)
[1]=>
int(2)
}
int(2)
array(2) {
[0]=>
int(1)
[1]=>
&int(2)
}
28 changes: 28 additions & 0 deletions Zend/tests/list/list_reference_004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
"Reference Unpacking - Foreach" list()
--FILE--
<?php
$coords = array(array(1, 2), array(3, 4));
foreach ($coords as [&$x, $y]) {
$x++;
$y++;
}
var_dump($coords);
?>
--EXPECTF--
array(2) {
[0]=>
array(2) {
[0]=>
int(2)
[1]=>
int(2)
}
[1]=>
array(2) {
[0]=>
&int(4)
[1]=>
int(4)
}
}
73 changes: 73 additions & 0 deletions Zend/tests/list/list_reference_005.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
--TEST--
"Reference Unpacking - Class Property and Methods" list()
--FILE--
<?php
class A {
public $a = [['hello']];
public $b = ['world'];

public function getVar() {
return $this->a;
}

public function &getVarRef() {
return $this->a;
}
}

class B {
static $a = [['world']];
}

$a = new A();
[&$var] = $a->a;
[&$var_too] = $a->b;
var_dump($a->a);
var_dump($a->b);

$a = new A();
[&$var] = $a->getVar();
var_dump($a->a);

$a = new A();
[&$var] = $a->getVarRef();
var_dump($a->a);

[&$var] = B::$a;
var_dump(B::$a);
?>
--EXPECTF--
array(1) {
[0]=>
&array(1) {
[0]=>
string(5) "hello"
}
}
array(1) {
[0]=>
&string(5) "world"
}

Notice: Attempting to set reference to non referenceable value in %s on line %d
array(1) {
[0]=>
array(1) {
[0]=>
string(5) "hello"
}
}
array(1) {
[0]=>
&array(1) {
[0]=>
string(5) "hello"
}
}
array(1) {
[0]=>
&array(1) {
[0]=>
string(5) "world"
}
}
58 changes: 58 additions & 0 deletions Zend/tests/list/list_reference_006.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
--TEST--
"Reference Unpacking - Class ArrayAccess No Reference" list()
--FILE--
<?php
class StorageNoRef implements ArrayAccess {
private $s = [];
function __construct(array $a) { $this->s = $a; }
function offsetSet ($k, $v) { $this->s[$k] = $v; }
function offsetGet ($k) { return $this->s[$k]; }
function offsetExists ($k) { return isset($this->s[$k]); }
function offsetUnset ($k) { unset($this->s[$k]); }
}

$a = new StorageNoRef([1, 2]);
list(&$one, $two) = $a;
var_dump($a);

$a = new StorageNoRef([1, 2]);
list(,,list($var)) = $a;
var_dump($a);

$a = new StorageNoRef(['one' => 1, 'two' => 2]);
['one' => &$one, 'two' => $two] = $a;
var_dump($a);
?>
--EXPECTF--
Notice: Indirect modification of overloaded element of %s has no effect in %s on line %d
object(StorageNoRef)#1 (1) {
["s":"StorageNoRef":private]=>
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
}

Notice: Undefined offset: 2 in %s on line %d
object(StorageNoRef)#2 (1) {
["s":"StorageNoRef":private]=>
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
}

Notice: Indirect modification of overloaded element of %s has no effect in %s on line %d
object(StorageNoRef)#1 (1) {
["s":"StorageNoRef":private]=>
array(2) {
["one"]=>
int(1)
["two"]=>
int(2)
}
}
Loading

0 comments on commit 6d4de4c

Please sign in to comment.