Skip to content

Commit fb02215

Browse files
committed
Allowed defaults on readonly properties
1 parent f820a54 commit fb02215

18 files changed

Lines changed: 471 additions & 8 deletions

Zend/tests/readonly_classes/readonly_class_inheritance_success.phpt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,22 @@ Readonly class can extend a readonly class
55

66
readonly class Foo
77
{
8+
public int $prop = 1;
89
}
910

1011
readonly class Bar extends Foo
1112
{
13+
public int $prop = 2;
1214
}
1315

16+
readonly class Baz extends Foo {}
17+
18+
var_dump(new Foo()->prop);
19+
var_dump(new Bar()->prop);
20+
var_dump(new Baz()->prop);
21+
1422
?>
1523
--EXPECT--
24+
int(1)
25+
int(2)
26+
int(1)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
Properties of a readonly class may have default values
3+
--FILE--
4+
<?php
5+
6+
readonly class Foo
7+
{
8+
public int $bar = 1;
9+
public ?string $nullable = null;
10+
11+
public function __construct()
12+
{
13+
try {
14+
$this->bar = 2;
15+
} catch (Error $e) {
16+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
17+
}
18+
}
19+
}
20+
21+
$foo = new Foo();
22+
var_dump($foo->bar);
23+
var_dump($foo->nullable);
24+
25+
try {
26+
$foo->bar = 3;
27+
} catch (Error $e) {
28+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
29+
}
30+
31+
?>
32+
--EXPECT--
33+
Error: Cannot modify readonly property Foo::$bar
34+
int(1)
35+
NULL
36+
Error: Cannot modify readonly property Foo::$bar
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Readonly class may use readonly trait property with default value
3+
--FILE--
4+
<?php
5+
6+
trait TDefault {
7+
public readonly int $prop = 2;
8+
}
9+
10+
readonly class C {
11+
use TDefault;
12+
}
13+
14+
var_dump(new C()->prop);
15+
16+
?>
17+
--EXPECT--
18+
int(2)

Zend/tests/readonly_props/readonly_clone_success1.phpt

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,41 @@ var_dump($foo2);
2323

2424
var_dump(clone $foo2);
2525

26+
class FooWithDefault {
27+
public readonly int $bar = 1;
28+
29+
public function __clone()
30+
{
31+
$this->bar++;
32+
}
33+
}
34+
35+
$fooWithDefault = new FooWithDefault();
36+
37+
var_dump(clone $fooWithDefault);
38+
39+
$fooWithDefault2 = clone $fooWithDefault;
40+
var_dump($fooWithDefault2);
41+
42+
var_dump(clone $fooWithDefault2);
43+
44+
class FooWithDefaultCloneWith {
45+
public readonly int $bar = 1;
46+
47+
public function withBar(int $bar)
48+
{
49+
return clone($this, ['bar' => $bar]);
50+
}
51+
}
52+
53+
$clone = new FooWithDefaultCloneWith();
54+
var_dump($clone);
55+
56+
$clone2 = $clone->withBar(2);
57+
var_dump($clone2);
58+
59+
var_dump($clone2->withBar(0));
60+
2661
?>
2762
--EXPECTF--
2863
object(Foo)#%d (%d) {
@@ -37,3 +72,27 @@ object(Foo)#%d (%d) {
3772
["bar"]=>
3873
int(3)
3974
}
75+
object(FooWithDefault)#%d (%d) {
76+
["bar"]=>
77+
int(2)
78+
}
79+
object(FooWithDefault)#%d (%d) {
80+
["bar"]=>
81+
int(2)
82+
}
83+
object(FooWithDefault)#%d (%d) {
84+
["bar"]=>
85+
int(3)
86+
}
87+
object(FooWithDefaultCloneWith)#%d (%d) {
88+
["bar"]=>
89+
int(1)
90+
}
91+
object(FooWithDefaultCloneWith)#%d (%d) {
92+
["bar"]=>
93+
int(2)
94+
}
95+
object(FooWithDefaultCloneWith)#%d (%d) {
96+
["bar"]=>
97+
int(0)
98+
}

Zend/tests/readonly_props/readonly_modification.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ class Test {
1414
}
1515
}
1616

17+
class TestWithDefault {
18+
public readonly int $prop = 1;
19+
20+
public function __construct() {
21+
try {
22+
$this->prop = 2;
23+
} catch (Error $e) {
24+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
25+
}
26+
}
27+
}
28+
1729
function byRef(&$ref) {}
1830

1931
$test = new Test;
@@ -66,6 +78,8 @@ try {
6678
echo $e->getMessage(), "\n";
6779
}
6880

81+
var_dump(new TestWithDefault()->prop);
82+
6983
?>
7084
--EXPECT--
7185
int(1)
@@ -80,3 +94,5 @@ array(0) {
8094
}
8195
Cannot indirectly modify readonly property Test::$prop2
8296
Cannot indirectly modify readonly property Test::$prop2
97+
Error: Cannot modify readonly property TestWithDefault::$prop
98+
int(1)

Zend/tests/readonly_props/readonly_trait_match.phpt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,20 @@ class C {
1313
use T1, T2;
1414
}
1515

16+
trait TDefault1 {
17+
public readonly int $prop = 1;
18+
}
19+
trait TDefault2 {
20+
public readonly int $prop = 1;
21+
}
22+
class CDefault {
23+
use TDefault1, TDefault2;
24+
}
25+
26+
var_dump(new CDefault()->prop);
27+
1628
?>
1729
===DONE===
1830
--EXPECT--
31+
int(1)
1932
===DONE===

Zend/tests/readonly_props/readonly_with_default.phpt

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,43 @@ Readonly property with default value
33
--FILE--
44
<?php
55

6+
enum E {
7+
case Case;
8+
}
9+
610
class Test {
711
public readonly int $prop = 1;
12+
public readonly string $className = self::class;
13+
public readonly ?string $nullable = null;
14+
public readonly array $array = [1, "two" => 2];
15+
public readonly E $enum = E::Case;
16+
public readonly string $enumString = E::Case->name;
817
}
918

1019
$test = new Test;
20+
var_dump($test->prop);
21+
var_dump($test->className);
22+
var_dump($test->nullable);
23+
var_dump($test->array);
24+
var_dump($test->enum);
25+
var_dump($test->enumString);
1126
try {
1227
$test->prop = 2;
1328
} catch (Error $e) {
14-
echo $e->getMessage(), "\n";
29+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
1530
}
1631

1732
?>
18-
--EXPECTF--
19-
Fatal error: Readonly property Test::$prop cannot have default value in %s on line %d
33+
--EXPECT--
34+
int(1)
35+
string(4) "Test"
36+
NULL
37+
array(2) {
38+
[0]=>
39+
int(1)
40+
["two"]=>
41+
int(2)
42+
}
43+
enum(E::Case)
44+
string(4) "Case"
45+
Error: Cannot modify readonly property Test::$prop
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Readonly property with default value has restricted set visibility for get/set abstract property
3+
--DESCRIPTION--
4+
The error message should be improved, the set access level comes from readonly.
5+
--FILE--
6+
<?php
7+
8+
abstract class P {
9+
public abstract int $prop { get; set; }
10+
}
11+
12+
class C extends P {
13+
public readonly int $prop = 42;
14+
}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Set access level of C::$prop must be omitted (as in class P) in %s on line %d
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Readonly property with default value and asymmetric visibility
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public readonly int $default = 1;
8+
public private(set) readonly int $private = 2;
9+
public protected(set) readonly int $protected = 3;
10+
public public(set) readonly int $public = 4;
11+
}
12+
13+
$test = new Test();
14+
var_dump($test->default, $test->private, $test->protected, $test->public);
15+
16+
foreach (['default', 'private', 'protected', 'public'] as $prop) {
17+
try {
18+
$test->$prop = 42;
19+
} catch (Error $e) {
20+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
21+
}
22+
}
23+
24+
?>
25+
--EXPECT--
26+
int(1)
27+
int(2)
28+
int(3)
29+
int(4)
30+
Error: Cannot modify readonly property Test::$default
31+
Error: Cannot modify readonly property Test::$private
32+
Error: Cannot modify readonly property Test::$protected
33+
Error: Cannot modify readonly property Test::$public
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
Readonly property with default value and inheritance
3+
--FILE--
4+
<?php
5+
6+
class ParentDefault {
7+
public readonly int $prop = 1;
8+
}
9+
10+
class ChildInherits extends ParentDefault {}
11+
12+
class ChildOverrides extends ParentDefault {
13+
public readonly int $prop = 2;
14+
}
15+
16+
class PrivateParent {
17+
private readonly int $prop = 3;
18+
19+
public function getParentProp(): int {
20+
return $this->prop;
21+
}
22+
}
23+
24+
class PrivateChild extends PrivateParent {
25+
public readonly int $prop = 4;
26+
}
27+
28+
var_dump(new ChildInherits()->prop);
29+
var_dump(new ChildOverrides()->prop);
30+
31+
$privateChild = new PrivateChild();
32+
var_dump($privateChild->getParentProp());
33+
var_dump($privateChild->prop);
34+
35+
?>
36+
--EXPECT--
37+
int(1)
38+
int(2)
39+
int(3)
40+
int(4)

0 commit comments

Comments
 (0)