Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,22 @@ Readonly class can extend a readonly class

readonly class Foo
{
public int $prop = 1;
}

readonly class Bar extends Foo
{
public int $prop = 2;
}

readonly class Baz extends Foo {}

var_dump(new Foo()->prop);
var_dump(new Bar()->prop);
var_dump(new Baz()->prop);

?>
--EXPECT--
int(1)
int(2)
int(1)
36 changes: 36 additions & 0 deletions Zend/tests/readonly_classes/readonly_with_property_default.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
Properties of a readonly class may have default values
--FILE--
<?php

readonly class Foo
{
public int $bar = 1;
public ?string $nullable = null;

public function __construct()
{
try {
$this->bar = 2;
} catch (Error $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
}
}

$foo = new Foo();
var_dump($foo->bar);
var_dump($foo->nullable);

try {
$foo->bar = 3;
} catch (Error $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}

?>
--EXPECT--
Error: Cannot modify readonly property Foo::$bar
int(1)
NULL
Error: Cannot modify readonly property Foo::$bar
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Readonly class may use readonly trait property with default value
--FILE--
<?php

trait TDefault {
public readonly int $prop = 2;
}

readonly class C {
use TDefault;
}

var_dump(new C()->prop);

?>
--EXPECT--
int(2)
30 changes: 30 additions & 0 deletions Zend/tests/readonly_props/readonly_clone_success1.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ var_dump($foo2);

var_dump(clone $foo2);

class FooWithDefault {
public readonly int $bar = 1;

public function __clone()
{
$this->bar++;
}
}

$fooWithDefault = new FooWithDefault();

var_dump(clone $fooWithDefault);

$fooWithDefault2 = clone $fooWithDefault;
var_dump($fooWithDefault2);

var_dump(clone $fooWithDefault2);

?>
--EXPECTF--
object(Foo)#%d (%d) {
Expand All @@ -37,3 +55,15 @@ object(Foo)#%d (%d) {
["bar"]=>
int(3)
}
object(FooWithDefault)#%d (%d) {
["bar"]=>
int(2)
}
object(FooWithDefault)#%d (%d) {
["bar"]=>
int(2)
}
object(FooWithDefault)#%d (%d) {
["bar"]=>
int(3)
}
16 changes: 16 additions & 0 deletions Zend/tests/readonly_props/readonly_modification.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ class Test {
}
}

class TestWithDefault {
public readonly int $prop = 1;

public function __construct() {
try {
$this->prop = 2;
} catch (Error $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
}
}

function byRef(&$ref) {}

$test = new Test;
Expand Down Expand Up @@ -66,6 +78,8 @@ try {
echo $e->getMessage(), "\n";
}

var_dump(new TestWithDefault()->prop);

?>
--EXPECT--
int(1)
Expand All @@ -80,3 +94,5 @@ array(0) {
}
Cannot indirectly modify readonly property Test::$prop2
Cannot indirectly modify readonly property Test::$prop2
Error: Cannot modify readonly property TestWithDefault::$prop
int(1)
13 changes: 13 additions & 0 deletions Zend/tests/readonly_props/readonly_trait_match.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,20 @@ class C {
use T1, T2;
}

trait TDefault1 {
public readonly int $prop = 1;
}
trait TDefault2 {
public readonly int $prop = 1;
}
class CDefault {
use TDefault1, TDefault2;
}

var_dump(new CDefault()->prop);

?>
===DONE===
--EXPECT--
int(1)
===DONE===
32 changes: 29 additions & 3 deletions Zend/tests/readonly_props/readonly_with_default.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,43 @@ Readonly property with default value
--FILE--
<?php

enum E {
case Case;
}

class Test {
public readonly int $prop = 1;
public readonly string $className = self::class;
public readonly ?string $nullable = null;
public readonly array $array = [1, "two" => 2];
public readonly E $enum = E::Case;
public readonly string $enumString = E::Case->name;
}

$test = new Test;
var_dump($test->prop);
var_dump($test->className);
var_dump($test->nullable);
var_dump($test->array);
var_dump($test->enum);
var_dump($test->enumString);
try {
$test->prop = 2;
} catch (Error $e) {
echo $e->getMessage(), "\n";
echo $e::class, ": ", $e->getMessage(), "\n";
}

?>
--EXPECTF--
Fatal error: Readonly property Test::$prop cannot have default value in %s on line %d
--EXPECT--
int(1)
string(4) "Test"
NULL
array(2) {
[0]=>
int(1)
["two"]=>
int(2)
}
enum(E::Case)
string(4) "Case"
Error: Cannot modify readonly property Test::$prop
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--TEST--
Readonly property with default value and asymmetric visibility
--FILE--
<?php

class Test {
public readonly int $default = 1;
public private(set) readonly int $private = 2;
public protected(set) readonly int $protected = 3;
public public(set) readonly int $public = 4;
}

$test = new Test();
var_dump($test->default, $test->private, $test->protected, $test->public);

foreach (['default', 'private', 'protected', 'public'] as $prop) {
try {
$test->$prop = 42;
} catch (Error $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
}

?>
--EXPECT--
int(1)
int(2)
int(3)
int(4)
Error: Cannot modify readonly property Test::$default
Error: Cannot modify readonly property Test::$private
Error: Cannot modify readonly property Test::$protected
Error: Cannot modify readonly property Test::$public
40 changes: 40 additions & 0 deletions Zend/tests/readonly_props/readonly_with_default_inheritance.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
--TEST--
Readonly property with default value and inheritance
--FILE--
<?php

class ParentDefault {
public readonly int $prop = 1;
}

class ChildInherits extends ParentDefault {}

class ChildOverrides extends ParentDefault {
public readonly int $prop = 2;
}

class PrivateParent {
private readonly int $prop = 3;

public function getParentProp(): int {
return $this->prop;
}
}

class PrivateChild extends PrivateParent {
public readonly int $prop = 4;
}

var_dump(new ChildInherits()->prop);
var_dump(new ChildOverrides()->prop);

$privateChild = new PrivateChild();
var_dump($privateChild->getParentProp());
var_dump($privateChild->prop);

?>
--EXPECT--
int(1)
int(2)
int(3)
int(4)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Readonly property with default value satisfies get-only interface property
--FILE--
<?php

interface I {
public int $prop { get; }
}

class C implements I {
public readonly int $prop = 42;
}

var_dump(new C()->prop);
?>
--EXPECTF--
int(42)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Readonly public(set) property with default value does not satisfy get/set interface property
--FILE--
<?php

interface I {
public int $prop { get; set; }
}

// does not satisfy set
class C implements I {
public public(set) readonly int $prop = 42;
}
?>
--EXPECTF--
Fatal error: Class C contains 1 abstract method and must therefore be declared abstract or implement the remaining method (I::$prop::set) in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Readonly property with default value has restricted set visibility for get/set interface property
--DESCRIPTION--
The error message should be improved, the set access level comes from readonly. Ref: Zend/tests/property_hooks/interface_get_set_readonly.phpt
--FILE--
<?php

interface I {
public int $prop { get; set; }
}

class C implements I {
public readonly int $prop = 42;
}
?>
--EXPECTF--
Fatal error: Set access level of C::$prop must be omitted (as in class I) in %s on line %d
35 changes: 35 additions & 0 deletions Zend/tests/readonly_props/readonly_with_default_reflection.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
--TEST--
Reflection for readonly property with default value
--FILE--
<?php

class Foo {
public readonly int $prop = 1;
public readonly ?string $nullable = null;
}

$rp = new ReflectionProperty(Foo::class, 'prop');
var_dump($rp->isReadOnly());
var_dump($rp->hasDefaultValue());
var_dump($rp->getDefaultValue());
var_dump(new ReflectionClass(Foo::class)->getDefaultProperties());

$test = new Foo();
try {
$rp->setValue($test, 2);
} catch (Error $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}

?>
--EXPECT--
bool(true)
bool(true)
int(1)
array(2) {
["prop"]=>
int(1)
["nullable"]=>
NULL
}
Error: Cannot modify readonly property Foo::$prop
Loading