Skip to content

[RFC] Extend #[\Override] to target properties #19061

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 12, 2025
Merged
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
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ PHP NEWS
. The backtick operator as an alias for shell_exec() has been deprecated.
(timwolla)
. Returning null from __debugInfo() has been deprecated. (DanielEScherzer)
. Support #[\Override] on properties. (Jiří Pudil)

- Date:
. The DATE_RFC7231 and DateTimeInterface::RFC7231 constants have been
Expand Down
2 changes: 2 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ PHP 8.5 UPGRADE NOTES
RFC: https://wiki.php.net/rfc/pipe-operator-v3
. Constructor property promotion can now be used for final properties.
RFC: https://wiki.php.net/rfc/final_promotion
. #[\Override] can now be applied to properties.
RFC: https://wiki.php.net/rfc/override_properties

- Curl:
. Added support for share handles that are persisted across multiple PHP
Expand Down
39 changes: 39 additions & 0 deletions Zend/tests/attributes/override/properties_01.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
--TEST--
#[\Override]: Properties
--FILE--
<?php

interface I {
public mixed $i { get; }
}

interface II extends I {
#[\Override]
public mixed $i { get; }
}

class P {
public mixed $p1;
public mixed $p2;
}

class PP extends P {
#[\Override]
public mixed $p1;
public mixed $p2;
}

class C extends PP implements I {
#[\Override]
public mixed $i;
#[\Override]
public mixed $p1;
public mixed $p2;
public mixed $c;
}

echo "Done";

?>
--EXPECT--
Done
15 changes: 15 additions & 0 deletions Zend/tests/attributes/override/properties_02.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
#[\Override]: Properties: No parent class.
--FILE--
<?php

class C {
#[\Override]
public mixed $c;
}

echo "Done";

?>
--EXPECTF--
Fatal error: C::$c has #[\Override] attribute, but no matching parent property exists in %s on line %d
21 changes: 21 additions & 0 deletions Zend/tests/attributes/override/properties_03.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
#[\Override]: Properties: No parent class, but child implements matching interface.
--FILE--
<?php

interface I {
public mixed $i { get; }
}

class P {
#[\Override]
public mixed $i;
}

class C extends P implements I {}

echo "Done";

?>
--EXPECTF--
Fatal error: P::$i has #[\Override] attribute, but no matching parent property exists in %s on line %d
21 changes: 21 additions & 0 deletions Zend/tests/attributes/override/properties_04.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
#[\Override]: Properties: No parent class, but child implements matching interface (2).
--FILE--
<?php

interface I {
public mixed $i { get; }
}

class C extends P implements I {}

class P {
#[\Override]
public mixed $i;
}

echo "Done";

?>
--EXPECTF--
Fatal error: P::$i has #[\Override] attribute, but no matching parent property exists in %s on line %d
26 changes: 26 additions & 0 deletions Zend/tests/attributes/override/properties_05.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
#[\Override]: Properties: No parent interface.
--FILE--
<?php

interface I {
#[\Override]
public mixed $i { get; }
}

interface II extends I {}


class C implements II {
public mixed $i;
}

class C2 implements I {
public mixed $i;
}

echo "Done";

?>
--EXPECTF--
Fatal error: I::$i has #[\Override] attribute, but no matching parent property exists in %s on line %d
15 changes: 15 additions & 0 deletions Zend/tests/attributes/override/properties_06.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
#[\Override]: Properties: On trait.
--FILE--
<?php

trait T {
#[\Override]
public mixed $t;
}

echo "Done";

?>
--EXPECT--
Done
19 changes: 19 additions & 0 deletions Zend/tests/attributes/override/properties_07.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Properties: On used trait without parent property.
--FILE--
<?php

trait T {
#[\Override]
public mixed $t;
}

class Foo {
use T;
}

echo "Done";

?>
--EXPECTF--
Fatal error: Foo::$t has #[\Override] attribute, but no matching parent property exists in %s on line %d
23 changes: 23 additions & 0 deletions Zend/tests/attributes/override/properties_08.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
#[\Override]: Properties: On used trait with interface property.
--FILE--
<?php

trait T {
#[\Override]
public mixed $i;
}

interface I {
public mixed $i { get; }
}

class Foo implements I {
use T;
}

echo "Done";

?>
--EXPECT--
Done
19 changes: 19 additions & 0 deletions Zend/tests/attributes/override/properties_09.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Properties: Parent property is private, child property is public.
--FILE--
<?php

class P {
private mixed $p;
}

class C extends P {
#[\Override]
public mixed $p;
}

echo "Done";

?>
--EXPECTF--
Fatal error: C::$p has #[\Override] attribute, but no matching parent property exists in %s on line %d
19 changes: 19 additions & 0 deletions Zend/tests/attributes/override/properties_10.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Properties: Parent property is private, child property is private.
--FILE--
<?php

class P {
private mixed $p;
}

class C extends P {
#[\Override]
private mixed $p;
}

echo "Done";

?>
--EXPECTF--
Fatal error: C::$p has #[\Override] attribute, but no matching parent property exists in %s on line %d
19 changes: 19 additions & 0 deletions Zend/tests/attributes/override/properties_11.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Properties: Parent property is protected, child property is public.
--FILE--
<?php

class P {
protected mixed $p;
}

class C extends P {
#[\Override]
public mixed $p;
}

echo "Done";

?>
--EXPECT--
Done
19 changes: 19 additions & 0 deletions Zend/tests/attributes/override/properties_12.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Properties: Parent property is protected, child property is protected.
--FILE--
<?php

class P {
protected mixed $p;
}

class C extends P {
#[\Override]
protected mixed $p;
}

echo "Done";

?>
--EXPECT--
Done
21 changes: 21 additions & 0 deletions Zend/tests/attributes/override/properties_13.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
#[\Override]: Properties: Redeclared trait property.
--FILE--
<?php

trait T {
public mixed $t;
}

class C {
use T;

#[\Override]
public mixed $t;
}

echo "Done";

?>
--EXPECTF--
Fatal error: C::$t has #[\Override] attribute, but no matching parent property exists in %s on line %d
25 changes: 25 additions & 0 deletions Zend/tests/attributes/override/properties_14.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--TEST--
#[\Override]: Properties: Redeclared trait property with interface.
--FILE--
<?php

interface I {
public mixed $i { get; }
}

trait T {
public mixed $i;
}

class C implements I {
use T;

#[\Override]
public mixed $i;
}

echo "Done";

?>
--EXPECT--
Done
19 changes: 19 additions & 0 deletions Zend/tests/attributes/override/properties_15.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
#[\Override]: Properties: Valid anonymous class.
--FILE--
<?php

interface I {
public mixed $i { get; }
}

new class () implements I {
#[\Override]
public mixed $i;
};

echo "Done";

?>
--EXPECT--
Done
21 changes: 21 additions & 0 deletions Zend/tests/attributes/override/properties_16.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
#[\Override]: Properties: Invalid anonymous class.
--FILE--
<?php

interface I {
public mixed $i { get; }
}

new class () implements I {
public mixed $i;

#[\Override]
public mixed $c;
};

echo "Done";

?>
--EXPECTF--
Fatal error: I@anonymous::$c has #[\Override] attribute, but no matching parent property exists in %s on line %d
16 changes: 16 additions & 0 deletions Zend/tests/attributes/override/properties_17.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
#[\Override]: Properties: Static property no parent class.
--FILE--
<?php

class C
{
#[\Override]
public static mixed $c;
}

echo "Done";

?>
--EXPECTF--
Fatal error: C::$c has #[\Override] attribute, but no matching parent property exists in %s on line %d
Loading