Skip to content

Commit 52d3d0d

Browse files
committed
Add limited support for new in initializers
Add support for new expressions inside parameter default values, static variable initializers, global constant initializers and attribute arguments. RFC: https://wiki.php.net/rfc/new_in_initializers Closes GH-7153.
1 parent cce3165 commit 52d3d0d

21 files changed

+629
-22
lines changed

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ PHP 8.1 UPGRADE NOTES
193193
RFC: https://wiki.php.net/rfc/noreturn_type
194194
. Added support for fibers.
195195
RFC: https://wiki.php.net/rfc/fibers
196+
. It is now possible to use "new ClassName()" expressions as parameter
197+
default values, static variable and global constant initializers, as well
198+
as attribute arguments.
199+
RFC: https://wiki.php.net/rfc/new_in_initializers
196200
. File uploads now provide an additional full_path key, which contains the
197201
full path (rather than just the basename) of the uploaded file. This is
198202
intended for use in conjunction with "upload webkitdirectory".

Zend/tests/constexpr/new.phpt

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
--TEST--
2+
new in constant expressions
3+
--FILE--
4+
<?php
5+
6+
try {
7+
eval('static $a = new DoesNotExist;');
8+
} catch (Error $e) {
9+
echo $e->getMessage(), "\n";
10+
}
11+
12+
static $b = new stdClass;
13+
var_dump($b);
14+
15+
try {
16+
eval('static $c = new stdClass([] + 0);');
17+
} catch (Error $e) {
18+
echo $e->getMessage(), "\n";
19+
}
20+
21+
class Test {
22+
public function __construct(public $a, public $b) {}
23+
}
24+
25+
try {
26+
eval('static $d = new Test(new stdClass, [] + 0);');
27+
} catch (Error $e) {
28+
echo $e->getMessage(), "\n";
29+
}
30+
31+
static $e = new Test(new stdClass, 42);
32+
var_dump($e);
33+
34+
class Test2 {
35+
public function __construct() {
36+
echo "Side-effect\n";
37+
throw new Exception("Failed to construct");
38+
}
39+
}
40+
41+
try {
42+
eval('static $f = new Test2();');
43+
} catch (Exception $e) {
44+
echo $e->getMessage(), "\n";
45+
}
46+
47+
?>
48+
--EXPECT--
49+
Class "DoesNotExist" not found
50+
object(stdClass)#2 (0) {
51+
}
52+
Unsupported operand types: array + int
53+
Unsupported operand types: array + int
54+
object(Test)#4 (2) {
55+
["a"]=>
56+
object(stdClass)#1 (0) {
57+
}
58+
["b"]=>
59+
int(42)
60+
}
61+
Side-effect
62+
Failed to construct

Zend/tests/constexpr/new_allowed.phpt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Places where new is allowed
3+
--FILE--
4+
<?php
5+
6+
#[SomeAttribute(new stdClass)]
7+
class Test {
8+
public function __construct(
9+
public $prop = new stdClass,
10+
) {
11+
var_dump($prop);
12+
}
13+
}
14+
15+
function test($param = new stdClass) {
16+
static $var = new stdClass;
17+
var_dump($param, $var);
18+
}
19+
20+
const TEST = new stdClass;
21+
22+
new Test;
23+
test();
24+
var_dump(TEST);
25+
26+
?>
27+
--EXPECT--
28+
object(stdClass)#3 (0) {
29+
}
30+
object(stdClass)#2 (0) {
31+
}
32+
object(stdClass)#3 (0) {
33+
}
34+
object(stdClass)#1 (0) {
35+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
New with anonymous class is not supported in constant expressions
3+
--FILE--
4+
<?php
5+
6+
static $x = new class {};
7+
8+
?>
9+
--EXPECTF--
10+
Fatal error: Cannot use anonymous class in constant expression in %s on line %d
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
Check that const exprs are pre-evaluated in new arguments
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public function __construct(public $x) {}
8+
}
9+
function test(
10+
$a = new C(__CLASS__),
11+
$b = new C(__FUNCTION__),
12+
$c = new C(x: __FILE__),
13+
) {
14+
var_dump($a, $b, $c);
15+
}
16+
test();
17+
18+
// Check that nested new works as well.
19+
function test2($p = new C(new C(__FUNCTION__))) {
20+
var_dump($p);
21+
}
22+
test2();
23+
24+
?>
25+
--EXPECTF--
26+
object(C)#1 (1) {
27+
["x"]=>
28+
string(0) ""
29+
}
30+
object(C)#2 (1) {
31+
["x"]=>
32+
string(4) "test"
33+
}
34+
object(C)#3 (1) {
35+
["x"]=>
36+
string(%d) "%snew_arg_eval.php"
37+
}
38+
object(C)#3 (1) {
39+
["x"]=>
40+
object(C)#2 (1) {
41+
["x"]=>
42+
string(5) "test2"
43+
}
44+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Argument unpacking in new arguments in const expr (not yet supported)
3+
--FILE--
4+
<?php
5+
6+
static $x = new stdClass(...[0]);
7+
8+
?>
9+
--EXPECTF--
10+
Fatal error: Argument unpacking in constant expressions is not supported in %s on line %d
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Dynamic class name in new is not supported
3+
--FILE--
4+
<?php
5+
6+
static $x = new (FOO);
7+
8+
?>
9+
--EXPECTF--
10+
Fatal error: Cannot use dynamic class name in constant expression in %s on line %d
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Invalid operation in new arg in const expr
3+
--FILE--
4+
<?php
5+
6+
static $x = new stdClass($foo);
7+
8+
?>
9+
--EXPECTF--
10+
Fatal error: Constant expression contains invalid operations in %s on line %d
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
Named params in new in const expr
3+
--FILE--
4+
<?php
5+
6+
class Vec {
7+
public function __construct(public float $x, public float $y, public float $z) {}
8+
}
9+
10+
static $a = new Vec(x: 0.0, y: 1.0, z: 2.0);
11+
var_dump($a);
12+
13+
static $b = new Vec(z: 0.0, y: 1.0, x: 2.0);
14+
var_dump($b);
15+
16+
static $c = new Vec(0.0, z: 1.0, y: 2.0);
17+
var_dump($c);
18+
19+
try {
20+
eval('static $d = new Vec(x: 0.0, x: 1.0);');
21+
} catch (Error $e) {
22+
echo $e->getMessage(), "\n";
23+
}
24+
25+
?>
26+
--EXPECT--
27+
object(Vec)#1 (3) {
28+
["x"]=>
29+
float(0)
30+
["y"]=>
31+
float(1)
32+
["z"]=>
33+
float(2)
34+
}
35+
object(Vec)#2 (3) {
36+
["x"]=>
37+
float(2)
38+
["y"]=>
39+
float(1)
40+
["z"]=>
41+
float(0)
42+
}
43+
object(Vec)#3 (3) {
44+
["x"]=>
45+
float(0)
46+
["y"]=>
47+
float(2)
48+
["z"]=>
49+
float(1)
50+
}
51+
Named parameter $x overwrites previous argument
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
New not allowed in class constant
3+
--FILE--
4+
<?php
5+
6+
// New in class constants (and static properties) brings up evaluation order questions: When
7+
// should the (potentially side-effecting) new expression be evaluated? Evaluating it when the
8+
// class is declared would break references to classes that are declared later in the same
9+
// file. On the other hand, the current lazy evaluation of initializers is somewhat ill-defined
10+
// when we start considering side-effecting expressions.
11+
12+
class Test {
13+
const X = new stdClass;
14+
}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: New expressions are not supported in this context in %s on line %d

0 commit comments

Comments
 (0)