mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
RFC: Add #[Override] attribute (#9836)
* Add #[Override] attribute * Move #[\Override] tests into Zend/tests/attributes/override/ * Check `check_only` before removing `ZEND_ACC_OVERRIDE` * NEWS/UPGRADING for #[\Override]
This commit is contained in:
1
NEWS
1
NEWS
@@ -9,6 +9,7 @@ PHP NEWS
|
|||||||
(ilutov)
|
(ilutov)
|
||||||
. Fixed GH-11488 (Missing "Optional parameter before required" deprecation on
|
. Fixed GH-11488 (Missing "Optional parameter before required" deprecation on
|
||||||
union null type). (ilutov)
|
union null type). (ilutov)
|
||||||
|
. Implement the #[\Override] attribute RFC. (timwolla)
|
||||||
|
|
||||||
- DOM:
|
- DOM:
|
||||||
. Fixed bug GH-11500 (Namespace reuse in createElementNS() generates wrong
|
. Fixed bug GH-11500 (Namespace reuse in createElementNS() generates wrong
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ PHP 8.3 UPGRADE NOTES
|
|||||||
declarations. RFC: https://wiki.php.net/rfc/typed_class_constants
|
declarations. RFC: https://wiki.php.net/rfc/typed_class_constants
|
||||||
. Closures created from magic methods can now accept named arguments.
|
. Closures created from magic methods can now accept named arguments.
|
||||||
. The final modifier may now be used when using a method from a trait.
|
. The final modifier may now be used when using a method from a trait.
|
||||||
|
. Added the #[\Override] attribute to check that a method exists
|
||||||
|
in a parent class or implemented interface.
|
||||||
|
RFC: https://wiki.php.net/rfc/marking_overriden_methods
|
||||||
|
|
||||||
- Posix
|
- Posix
|
||||||
. posix_getrlimit() now takes an optional $res parameter to allow fetching a
|
. posix_getrlimit() now takes an optional $res parameter to allow fetching a
|
||||||
|
|||||||
47
Zend/tests/attributes/override/001.phpt
Normal file
47
Zend/tests/attributes/override/001.phpt
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
public function i();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface II extends I {
|
||||||
|
#[\Override]
|
||||||
|
public function i();
|
||||||
|
}
|
||||||
|
|
||||||
|
class P {
|
||||||
|
public function p1() {}
|
||||||
|
public function p2() {}
|
||||||
|
public function p3() {}
|
||||||
|
public function p4() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PP extends P {
|
||||||
|
#[\Override]
|
||||||
|
public function p1() {}
|
||||||
|
public function p2() {}
|
||||||
|
#[\Override]
|
||||||
|
public function p3() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends PP implements I {
|
||||||
|
#[\Override]
|
||||||
|
public function i() {}
|
||||||
|
#[\Override]
|
||||||
|
public function p1() {}
|
||||||
|
#[\Override]
|
||||||
|
public function p2() {}
|
||||||
|
public function p3() {}
|
||||||
|
#[\Override]
|
||||||
|
public function p4() {}
|
||||||
|
public function c() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
19
Zend/tests/attributes/override/002.phpt
Normal file
19
Zend/tests/attributes/override/002.phpt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Valid native interface.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Foo implements IteratorAggregate
|
||||||
|
{
|
||||||
|
#[\Override]
|
||||||
|
public function getIterator(): Traversable
|
||||||
|
{
|
||||||
|
yield from [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
16
Zend/tests/attributes/override/003.phpt
Normal file
16
Zend/tests/attributes/override/003.phpt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: No parent class.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class C
|
||||||
|
{
|
||||||
|
#[\Override]
|
||||||
|
public function c(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: C::c() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
21
Zend/tests/attributes/override/004.phpt
Normal file
21
Zend/tests/attributes/override/004.phpt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: No parent class, but child implements matching interface.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
public function i(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class P {
|
||||||
|
#[\Override]
|
||||||
|
public function i(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends P implements I {}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: P::i() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
21
Zend/tests/attributes/override/005.phpt
Normal file
21
Zend/tests/attributes/override/005.phpt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: No parent class, but child implements matching interface (2).
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
public function i(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends P implements I {}
|
||||||
|
|
||||||
|
class P {
|
||||||
|
#[\Override]
|
||||||
|
public function i(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: P::i() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
26
Zend/tests/attributes/override/006.phpt
Normal file
26
Zend/tests/attributes/override/006.phpt
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: No parent interface.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
#[\Override]
|
||||||
|
public function i(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface II extends I {}
|
||||||
|
|
||||||
|
|
||||||
|
class C implements II {
|
||||||
|
public function i(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C2 implements I {
|
||||||
|
public function i(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: I::i() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
15
Zend/tests/attributes/override/007.phpt
Normal file
15
Zend/tests/attributes/override/007.phpt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: On trait.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
trait T {
|
||||||
|
#[\Override]
|
||||||
|
public function t(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
19
Zend/tests/attributes/override/008.phpt
Normal file
19
Zend/tests/attributes/override/008.phpt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: On used trait without parent method.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
trait T {
|
||||||
|
#[\Override]
|
||||||
|
public function t(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
use T;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Foo::t() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
23
Zend/tests/attributes/override/009.phpt
Normal file
23
Zend/tests/attributes/override/009.phpt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: On used trait with interface method.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
trait T {
|
||||||
|
#[\Override]
|
||||||
|
public function i(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
public function i(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo implements I {
|
||||||
|
use T;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
19
Zend/tests/attributes/override/010.phpt
Normal file
19
Zend/tests/attributes/override/010.phpt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Parent method is private.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class P {
|
||||||
|
private function p(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends P {
|
||||||
|
#[\Override]
|
||||||
|
public function p(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: C::p() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
19
Zend/tests/attributes/override/011.phpt
Normal file
19
Zend/tests/attributes/override/011.phpt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Parent method is private (2).
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class P {
|
||||||
|
private function p(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends P {
|
||||||
|
#[\Override]
|
||||||
|
private function p(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: C::p() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
19
Zend/tests/attributes/override/012.phpt
Normal file
19
Zend/tests/attributes/override/012.phpt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Parent method is protected.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class P {
|
||||||
|
protected function p(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends P {
|
||||||
|
#[\Override]
|
||||||
|
public function p(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
19
Zend/tests/attributes/override/013.phpt
Normal file
19
Zend/tests/attributes/override/013.phpt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Parent method is protected (2).
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class P {
|
||||||
|
protected function p(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends P {
|
||||||
|
#[\Override]
|
||||||
|
protected function p(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
18
Zend/tests/attributes/override/014.phpt
Normal file
18
Zend/tests/attributes/override/014.phpt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: enum without interface.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
enum E {
|
||||||
|
case One;
|
||||||
|
case Two;
|
||||||
|
|
||||||
|
#[\Override]
|
||||||
|
public function e(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: E::e() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
22
Zend/tests/attributes/override/015.phpt
Normal file
22
Zend/tests/attributes/override/015.phpt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: enum with matching interface.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
public function e(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum E implements I {
|
||||||
|
case One;
|
||||||
|
case Two;
|
||||||
|
|
||||||
|
#[\Override]
|
||||||
|
public function e(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
21
Zend/tests/attributes/override/016.phpt
Normal file
21
Zend/tests/attributes/override/016.phpt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Declared abstract trait method.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
trait T {
|
||||||
|
public abstract function t(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
use T;
|
||||||
|
|
||||||
|
#[\Override]
|
||||||
|
public function t(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
21
Zend/tests/attributes/override/017.phpt
Normal file
21
Zend/tests/attributes/override/017.phpt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Redeclared trait method.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
trait T {
|
||||||
|
public function t(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
use T;
|
||||||
|
|
||||||
|
#[\Override]
|
||||||
|
public function t(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: C::t() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
32
Zend/tests/attributes/override/018.phpt
Normal file
32
Zend/tests/attributes/override/018.phpt
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Redeclared trait method with interface.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
public function i(): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait T {
|
||||||
|
public function i(): string {
|
||||||
|
return 'T';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C implements I {
|
||||||
|
use T;
|
||||||
|
|
||||||
|
#[\Override]
|
||||||
|
public function i(): string {
|
||||||
|
return 'C';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump((new C())->i());
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
string(1) "C"
|
||||||
|
Done
|
||||||
19
Zend/tests/attributes/override/019.phpt
Normal file
19
Zend/tests/attributes/override/019.phpt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Valid anonymous class.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
public function i(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
new class () implements I {
|
||||||
|
#[\Override]
|
||||||
|
public function i(): void {}
|
||||||
|
};
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
21
Zend/tests/attributes/override/020.phpt
Normal file
21
Zend/tests/attributes/override/020.phpt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Invalid anonymous class.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
public function i(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
new class () implements I {
|
||||||
|
public function i(): void {}
|
||||||
|
|
||||||
|
#[\Override]
|
||||||
|
public function c(): void {}
|
||||||
|
};
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: I@anonymous::c() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
19
Zend/tests/attributes/override/021.phpt
Normal file
19
Zend/tests/attributes/override/021.phpt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: __construct
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class P {
|
||||||
|
public function __construct() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends P {
|
||||||
|
#[\Override]
|
||||||
|
public function __construct() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: C::__construct() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
16
Zend/tests/attributes/override/022.phpt
Normal file
16
Zend/tests/attributes/override/022.phpt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Static method no parent class.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class C
|
||||||
|
{
|
||||||
|
#[\Override]
|
||||||
|
public static function c(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: C::c() has #[\Override] attribute, but no matching parent method exists in %s on line %d
|
||||||
19
Zend/tests/attributes/override/023.phpt
Normal file
19
Zend/tests/attributes/override/023.phpt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
--TEST--
|
||||||
|
#[\Override]: Static method.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class P {
|
||||||
|
public static function p(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends P {
|
||||||
|
#[\Override]
|
||||||
|
public static function p(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
@@ -29,6 +29,7 @@ ZEND_API zend_class_entry *zend_ce_return_type_will_change_attribute;
|
|||||||
ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties;
|
ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties;
|
||||||
ZEND_API zend_class_entry *zend_ce_sensitive_parameter;
|
ZEND_API zend_class_entry *zend_ce_sensitive_parameter;
|
||||||
ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
|
ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
|
||||||
|
ZEND_API zend_class_entry *zend_ce_override;
|
||||||
|
|
||||||
static zend_object_handlers attributes_object_handlers_sensitive_parameter_value;
|
static zend_object_handlers attributes_object_handlers_sensitive_parameter_value;
|
||||||
|
|
||||||
@@ -136,6 +137,11 @@ static HashTable *attributes_sensitive_parameter_value_get_properties_for(zend_o
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZEND_METHOD(Override, __construct)
|
||||||
|
{
|
||||||
|
ZEND_PARSE_PARAMETERS_NONE();
|
||||||
|
}
|
||||||
|
|
||||||
static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
|
static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
|
||||||
{
|
{
|
||||||
if (attributes) {
|
if (attributes) {
|
||||||
@@ -371,6 +377,9 @@ void zend_register_attribute_ce(void)
|
|||||||
/* This is not an actual attribute, thus the zend_mark_internal_attribute() call is missing. */
|
/* This is not an actual attribute, thus the zend_mark_internal_attribute() call is missing. */
|
||||||
zend_ce_sensitive_parameter_value = register_class_SensitiveParameterValue();
|
zend_ce_sensitive_parameter_value = register_class_SensitiveParameterValue();
|
||||||
zend_ce_sensitive_parameter_value->default_object_handlers = &attributes_object_handlers_sensitive_parameter_value;
|
zend_ce_sensitive_parameter_value->default_object_handlers = &attributes_object_handlers_sensitive_parameter_value;
|
||||||
|
|
||||||
|
zend_ce_override = register_class_Override();
|
||||||
|
zend_mark_internal_attribute(zend_ce_override);
|
||||||
}
|
}
|
||||||
|
|
||||||
void zend_attributes_shutdown(void)
|
void zend_attributes_shutdown(void)
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ extern ZEND_API zend_class_entry *zend_ce_attribute;
|
|||||||
extern ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties;
|
extern ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties;
|
||||||
extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter;
|
extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter;
|
||||||
extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
|
extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
|
||||||
|
extern ZEND_API zend_class_entry *zend_ce_override;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
zend_string *name;
|
zend_string *name;
|
||||||
|
|||||||
@@ -86,3 +86,12 @@ final class SensitiveParameterValue
|
|||||||
|
|
||||||
public function __debugInfo(): array {}
|
public function __debugInfo(): array {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @strict-properties
|
||||||
|
*/
|
||||||
|
#[Attribute(Attribute::TARGET_METHOD)]
|
||||||
|
final class Override
|
||||||
|
{
|
||||||
|
public function __construct() {}
|
||||||
|
}
|
||||||
|
|||||||
29
Zend/zend_attributes_arginfo.h
generated
29
Zend/zend_attributes_arginfo.h
generated
@@ -1,5 +1,5 @@
|
|||||||
/* This is a generated file, edit the .stub.php file instead.
|
/* This is a generated file, edit the .stub.php file instead.
|
||||||
* Stub hash: afb6a3f1d14099066d028b1579fff074359da293 */
|
* Stub hash: ab85fd8b8d2b1f1d2bc6c72c9663b112b8d6d2f8 */
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0)
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0)
|
||||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL")
|
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL")
|
||||||
@@ -22,6 +22,8 @@ ZEND_END_ARG_INFO()
|
|||||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SensitiveParameterValue___debugInfo, 0, 0, IS_ARRAY, 0)
|
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SensitiveParameterValue___debugInfo, 0, 0, IS_ARRAY, 0)
|
||||||
ZEND_END_ARG_INFO()
|
ZEND_END_ARG_INFO()
|
||||||
|
|
||||||
|
#define arginfo_class_Override___construct arginfo_class_ReturnTypeWillChange___construct
|
||||||
|
|
||||||
|
|
||||||
ZEND_METHOD(Attribute, __construct);
|
ZEND_METHOD(Attribute, __construct);
|
||||||
ZEND_METHOD(ReturnTypeWillChange, __construct);
|
ZEND_METHOD(ReturnTypeWillChange, __construct);
|
||||||
@@ -30,6 +32,7 @@ ZEND_METHOD(SensitiveParameter, __construct);
|
|||||||
ZEND_METHOD(SensitiveParameterValue, __construct);
|
ZEND_METHOD(SensitiveParameterValue, __construct);
|
||||||
ZEND_METHOD(SensitiveParameterValue, getValue);
|
ZEND_METHOD(SensitiveParameterValue, getValue);
|
||||||
ZEND_METHOD(SensitiveParameterValue, __debugInfo);
|
ZEND_METHOD(SensitiveParameterValue, __debugInfo);
|
||||||
|
ZEND_METHOD(Override, __construct);
|
||||||
|
|
||||||
|
|
||||||
static const zend_function_entry class_Attribute_methods[] = {
|
static const zend_function_entry class_Attribute_methods[] = {
|
||||||
@@ -63,6 +66,12 @@ static const zend_function_entry class_SensitiveParameterValue_methods[] = {
|
|||||||
ZEND_FE_END
|
ZEND_FE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const zend_function_entry class_Override_methods[] = {
|
||||||
|
ZEND_ME(Override, __construct, arginfo_class_Override___construct, ZEND_ACC_PUBLIC)
|
||||||
|
ZEND_FE_END
|
||||||
|
};
|
||||||
|
|
||||||
static zend_class_entry *register_class_Attribute(void)
|
static zend_class_entry *register_class_Attribute(void)
|
||||||
{
|
{
|
||||||
zend_class_entry ce, *class_entry;
|
zend_class_entry ce, *class_entry;
|
||||||
@@ -205,3 +214,21 @@ static zend_class_entry *register_class_SensitiveParameterValue(void)
|
|||||||
|
|
||||||
return class_entry;
|
return class_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static zend_class_entry *register_class_Override(void)
|
||||||
|
{
|
||||||
|
zend_class_entry ce, *class_entry;
|
||||||
|
|
||||||
|
INIT_CLASS_ENTRY(ce, "Override", class_Override_methods);
|
||||||
|
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||||
|
class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES;
|
||||||
|
|
||||||
|
zend_string *attribute_name_Attribute_class_Override = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1);
|
||||||
|
zend_attribute *attribute_Attribute_class_Override = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_Override, 1);
|
||||||
|
zend_string_release(attribute_name_Attribute_class_Override);
|
||||||
|
zval attribute_Attribute_class_Override_arg0;
|
||||||
|
ZVAL_LONG(&attribute_Attribute_class_Override_arg0, ZEND_ATTRIBUTE_TARGET_METHOD);
|
||||||
|
ZVAL_COPY_VALUE(&attribute_Attribute_class_Override->args[0].value, &attribute_Attribute_class_Override_arg0);
|
||||||
|
|
||||||
|
return class_entry;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7538,6 +7538,16 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
zend_compile_attributes(&op_array->attributes, decl->child[4], 0, target, 0);
|
zend_compile_attributes(&op_array->attributes, decl->child[4], 0, target, 0);
|
||||||
|
|
||||||
|
zend_attribute *override_attribute = zend_get_attribute_str(
|
||||||
|
op_array->attributes,
|
||||||
|
"override",
|
||||||
|
sizeof("override")-1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (override_attribute) {
|
||||||
|
op_array->fn_flags |= ZEND_ACC_OVERRIDE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do not leak the class scope into free standing functions, even if they are dynamically
|
/* Do not leak the class scope into free standing functions, even if they are dynamically
|
||||||
@@ -8106,6 +8116,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
|
|||||||
} else if (EXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL)) {
|
} else if (EXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL)) {
|
||||||
zend_string_release(lcname);
|
zend_string_release(lcname);
|
||||||
zend_build_properties_info_table(ce);
|
zend_build_properties_info_table(ce);
|
||||||
|
zend_inheritance_check_override(ce);
|
||||||
ce->ce_flags |= ZEND_ACC_LINKED;
|
ce->ce_flags |= ZEND_ACC_LINKED;
|
||||||
zend_observer_class_linked_notify(ce, lcname);
|
zend_observer_class_linked_notify(ce, lcname);
|
||||||
return;
|
return;
|
||||||
@@ -8116,6 +8127,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
|
|||||||
link_unbound:
|
link_unbound:
|
||||||
/* Link unbound simple class */
|
/* Link unbound simple class */
|
||||||
zend_build_properties_info_table(ce);
|
zend_build_properties_info_table(ce);
|
||||||
|
zend_inheritance_check_override(ce);
|
||||||
ce->ce_flags |= ZEND_ACC_LINKED;
|
ce->ce_flags |= ZEND_ACC_LINKED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ typedef struct _zend_oparray_context {
|
|||||||
/* Class cannot be serialized or unserialized | | | */
|
/* Class cannot be serialized or unserialized | | | */
|
||||||
#define ZEND_ACC_NOT_SERIALIZABLE (1 << 29) /* X | | | */
|
#define ZEND_ACC_NOT_SERIALIZABLE (1 << 29) /* X | | | */
|
||||||
/* | | | */
|
/* | | | */
|
||||||
/* Function Flags (unused: 28-30) | | | */
|
/* Function Flags (unused: 29-30) | | | */
|
||||||
/* ============== | | | */
|
/* ============== | | | */
|
||||||
/* | | | */
|
/* | | | */
|
||||||
/* deprecation flag | | | */
|
/* deprecation flag | | | */
|
||||||
@@ -363,6 +363,9 @@ typedef struct _zend_oparray_context {
|
|||||||
/* supports opcache compile-time evaluation (funcs) | | | */
|
/* supports opcache compile-time evaluation (funcs) | | | */
|
||||||
#define ZEND_ACC_COMPILE_TIME_EVAL (1 << 27) /* | X | | */
|
#define ZEND_ACC_COMPILE_TIME_EVAL (1 << 27) /* | X | | */
|
||||||
/* | | | */
|
/* | | | */
|
||||||
|
/* has #[\Override] attribute | | | */
|
||||||
|
#define ZEND_ACC_OVERRIDE (1 << 28) /* | X | | */
|
||||||
|
/* | | | */
|
||||||
/* op_array uses strict mode types | | | */
|
/* op_array uses strict mode types | | | */
|
||||||
#define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */
|
#define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */
|
||||||
|
|
||||||
|
|||||||
@@ -1174,6 +1174,11 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex(
|
|||||||
}
|
}
|
||||||
perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
|
perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!check_only && child->common.scope == ce) {
|
||||||
|
child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
|
||||||
|
}
|
||||||
|
|
||||||
return INHERITANCE_SUCCESS;
|
return INHERITANCE_SUCCESS;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
@@ -1896,6 +1901,28 @@ static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
|
||||||
|
void zend_inheritance_check_override(zend_class_entry *ce)
|
||||||
|
{
|
||||||
|
zend_function *f;
|
||||||
|
|
||||||
|
if (ce->ce_flags & ZEND_ACC_TRAIT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, f) {
|
||||||
|
if (f->common.fn_flags & ZEND_ACC_OVERRIDE) {
|
||||||
|
ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
|
||||||
|
|
||||||
|
zend_error_at_noreturn(
|
||||||
|
E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
|
||||||
|
"%s::%s() has #[\\Override] attribute, but no matching parent method exists",
|
||||||
|
ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
|
||||||
|
}
|
||||||
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
|
static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
|
||||||
{
|
{
|
||||||
/* self in trait methods should be resolved to the using class, not the trait. */
|
/* self in trait methods should be resolved to the using class, not the trait. */
|
||||||
@@ -2772,6 +2799,8 @@ static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
|
|||||||
check_variance_obligation(obligation);
|
check_variance_obligation(obligation);
|
||||||
} ZEND_HASH_FOREACH_END();
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
|
||||||
|
zend_inheritance_check_override(ce);
|
||||||
|
|
||||||
ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
|
ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
|
||||||
ce->ce_flags |= ZEND_ACC_LINKED;
|
ce->ce_flags |= ZEND_ACC_LINKED;
|
||||||
zend_hash_index_del(all_obligations, num_key);
|
zend_hash_index_del(all_obligations, num_key);
|
||||||
@@ -3131,6 +3160,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
|
|||||||
EG(record_errors) = orig_record_errors;
|
EG(record_errors) = orig_record_errors;
|
||||||
|
|
||||||
if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
|
if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
|
||||||
|
zend_inheritance_check_override(ce);
|
||||||
ce->ce_flags |= ZEND_ACC_LINKED;
|
ce->ce_flags |= ZEND_ACC_LINKED;
|
||||||
} else {
|
} else {
|
||||||
ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
|
ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
|
||||||
@@ -3342,6 +3372,7 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_
|
|||||||
if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
|
if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
|
||||||
zend_verify_abstract_class(ce);
|
zend_verify_abstract_class(ce);
|
||||||
}
|
}
|
||||||
|
zend_inheritance_check_override(ce);
|
||||||
ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
|
ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
|
||||||
ce->ce_flags |= ZEND_ACC_LINKED;
|
ce->ce_flags |= ZEND_ACC_LINKED;
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ void zend_verify_abstract_class(zend_class_entry *ce);
|
|||||||
void zend_build_properties_info_table(zend_class_entry *ce);
|
void zend_build_properties_info_table(zend_class_entry *ce);
|
||||||
ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding);
|
ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding);
|
||||||
|
|
||||||
|
void zend_inheritance_check_override(zend_class_entry *ce);
|
||||||
|
|
||||||
ZEND_API extern zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces);
|
ZEND_API extern zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces);
|
||||||
ZEND_API extern zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies);
|
ZEND_API extern zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user