Skip to content

Commit 4200794

Browse files
committed
Implement "Constructor Promotion"
1 parent e8e09b6 commit 4200794

16 files changed

+345
-10
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Constructor promotion cannot be used inside an abstract constructor
3+
--FILE--
4+
<?php
5+
6+
abstract class Test {
7+
abstract public function __construct(public int $x);
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Cannot declare promoted property in an abstract constructor in %s on line %d
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Constructor promotion only permits visibility modifiers
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public function __construct(public static $x) {}
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Parse error: syntax error, unexpected 'static' (T_STATIC), expecting variable (T_VARIABLE) in %s on line %d
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Constructor promotion (basic example)
3+
--FILE--
4+
<?php
5+
6+
class Point {
7+
public function __construct(public int $x, public int $y, public int $z) {}
8+
}
9+
10+
$point = new Point(1, 2, 3);
11+
12+
// Check that properties really are typed.
13+
try {
14+
$point->x = "foo";
15+
} catch (TypeError $e) {
16+
echo $e->getMessage(), "\n";
17+
}
18+
19+
?>
20+
--EXPECT--
21+
Cannot assign string to property Point::$x of type int
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Constructor promotion of by-ref parameter
3+
--FILE--
4+
<?php
5+
6+
class Ary {
7+
public function __construct(public array &$array) {}
8+
}
9+
10+
$array = [];
11+
$ary = new Ary($array);
12+
$array[] = 42;
13+
var_dump($ary->array);
14+
15+
?>
16+
--EXPECT--
17+
array(1) {
18+
[0]=>
19+
int(42)
20+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Type of promoted property may not be callable
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public function __construct(public callable $callable) {}
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Property Test::$callable cannot have type callable in %s on line %d
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
Constructor promotion with default values
3+
--FILE--
4+
<?php
5+
6+
class Point {
7+
public function __construct(
8+
public float $x = 0.0,
9+
public float $y = 1.0,
10+
public float $z = 2.0
11+
) {}
12+
}
13+
14+
var_dump(new Point(10.0));
15+
var_dump(new Point(10.0, 11.0));
16+
var_dump(new Point(10.0, 11.0, 12.0));
17+
18+
?>
19+
--EXPECT--
20+
object(Point)#1 (3) {
21+
["x"]=>
22+
float(10)
23+
["y"]=>
24+
float(1)
25+
["z"]=>
26+
float(2)
27+
}
28+
object(Point)#1 (3) {
29+
["x"]=>
30+
float(10)
31+
["y"]=>
32+
float(11)
33+
["z"]=>
34+
float(2)
35+
}
36+
object(Point)#1 (3) {
37+
["x"]=>
38+
float(10)
39+
["y"]=>
40+
float(11)
41+
["z"]=>
42+
float(12)
43+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Constructor promotion cannot be used inside an abstract constructor (interface variant)
3+
--FILE--
4+
<?php
5+
6+
interface Test {
7+
public function __construct(public int $x);
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Cannot declare promoted property in an abstract constructor in %s on line %d
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
Constructor promotiong mixed with other properties, parameters and code
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public string $prop2;
8+
9+
public function __construct(public string $prop1 = "", $param2 = "") {
10+
$this->prop2 = $prop1 . $param2;
11+
}
12+
}
13+
14+
var_dump(new Test("Foo", "Bar"));
15+
echo "\n";
16+
echo new ReflectionClass(Test::class), "\n";
17+
18+
?>
19+
--EXPECTF--
20+
object(Test)#1 (2) {
21+
["prop2"]=>
22+
string(6) "FooBar"
23+
["prop1"]=>
24+
string(3) "Foo"
25+
}
26+
27+
Class [ <user> class Test ] {
28+
@@ %s
29+
30+
- Constants [0] {
31+
}
32+
33+
- Static properties [0] {
34+
}
35+
36+
- Static methods [0] {
37+
}
38+
39+
- Properties [2] {
40+
Property [ <default> public $prop2 ]
41+
Property [ <default> public $prop1 ]
42+
}
43+
44+
- Methods [1] {
45+
Method [ <user, ctor> public method __construct ] {
46+
@@ %s
47+
48+
- Parameters [2] {
49+
Parameter #0 [ <optional> string $prop1 = '' ]
50+
Parameter #1 [ <optional> $param2 = '' ]
51+
}
52+
}
53+
}
54+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Constructor promotion can only be used in constructors ... duh
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public function foobar(public int $x, public int $y) {}
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Cannot declare promoted property outside a constructor in %s on line %d
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Constructor promotion with null default, requires an explicitly nullable type
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public function __construct(public int $x = null) {}
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Cannot use null as default value for parameter $x of type int in %s on line %d

0 commit comments

Comments
 (0)