Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0758e59

Browse filesBrowse files
committed
feature #45303 [ErrorHandler] Report overridden @Final constants (fancyweb)
This PR was merged into the 6.1 branch. Discussion ---------- [ErrorHandler] Report overridden @Final constants | Q | A | ------------- | --- | Branch? | 6.1 | Bug fix? | no | New feature? | yes | Deprecations? | - | Tickets | #44268 | License | MIT | Doc PR | - See #44268 and https://wiki.php.net/rfc/final_class_const. Commits ------- 0b82bda [ErrorHandler] Report overridden @Final constants
2 parents 568a79d + 0b82bda commit 0758e59
Copy full SHA for 0758e59

9 files changed

+180
-1
lines changed

‎src/Symfony/Component/ErrorHandler/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/ErrorHandler/CHANGELOG.md
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
6.1
5+
---
6+
7+
* Report overridden `@final` constants
8+
49
5.4
510
---
611

‎src/Symfony/Component/ErrorHandler/DebugClassLoader.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/ErrorHandler/DebugClassLoader.php
+21-1Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ class DebugClassLoader
112112
private static array $checkedClasses = [];
113113
private static array $final = [];
114114
private static array $finalMethods = [];
115+
private static array $finalConstants = [];
115116
private static array $deprecated = [];
116117
private static array $internal = [];
117118
private static array $internalMethods = [];
@@ -468,8 +469,9 @@ public function checkAnnotations(\ReflectionClass $refl, string $class): array
468469
self::$finalMethods[$class] = [];
469470
self::$internalMethods[$class] = [];
470471
self::$annotatedParameters[$class] = [];
472+
self::$finalConstants[$class] = [];
471473
foreach ($parentAndOwnInterfaces as $use) {
472-
foreach (['finalMethods', 'internalMethods', 'annotatedParameters', 'returnTypes'] as $property) {
474+
foreach (['finalMethods', 'internalMethods', 'annotatedParameters', 'returnTypes', 'finalConstants'] as $property) {
473475
if (isset(self::${$property}[$use])) {
474476
self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use];
475477
}
@@ -624,6 +626,24 @@ public function checkAnnotations(\ReflectionClass $refl, string $class): array
624626
}
625627
}
626628

629+
foreach ($refl->getReflectionConstants(\ReflectionClassConstant::IS_PUBLIC | \ReflectionClassConstant::IS_PROTECTED) as $constant) {
630+
if ($constant->class !== $class) {
631+
continue;
632+
}
633+
634+
foreach ($parentAndOwnInterfaces as $use) {
635+
if (isset(self::$finalConstants[$use][$constant->name])) {
636+
$deprecations[] = sprintf('The "%s::%s" constant is considered final. You should not override it in "%s".', self::$finalConstants[$use][$constant->name], $constant->name, $class);
637+
}
638+
}
639+
640+
if (!($doc = $this->parsePhpDoc($constant)) || !isset($doc['final'])) {
641+
continue;
642+
}
643+
644+
self::$finalConstants[$class][$constant->name] = $class;
645+
}
646+
627647
return $deprecations;
628648
}
629649

‎src/Symfony/Component/ErrorHandler/Tests/DebugClassLoaderTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/ErrorHandler/Tests/DebugClassLoaderTest.php
+37Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,43 @@ class_exists('Test\\'.ReturnType::class, true);
400400
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::static()" might add "static" as a native return type declaration in the future. Do the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" now to avoid errors or add an explicit @return annotation to suppress this message.',
401401
], $deprecations);
402402
}
403+
404+
public function testOverrideFinalConstant()
405+
{
406+
$deprecations = [];
407+
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
408+
$e = error_reporting(E_USER_DEPRECATED);
409+
410+
class_exists( Fixtures\FinalConstant\OverrideFinalConstant::class, true);
411+
412+
error_reporting($e);
413+
restore_error_handler();
414+
415+
$this->assertSame([
416+
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant\FinalConstants::OVERRIDDEN_FINAL_PARENT_CLASS" constant is considered final. You should not override it in "Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant\OverrideFinalConstant".',
417+
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant\FinalConstants2::OVERRIDDEN_FINAL_PARENT_PARENT_CLASS" constant is considered final. You should not override it in "Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant\OverrideFinalConstant".',
418+
], $deprecations);
419+
}
420+
421+
/**
422+
* @requires PHP 8.1
423+
*/
424+
public function testOverrideFinalConstant81()
425+
{
426+
$deprecations = [];
427+
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
428+
$e = error_reporting(E_USER_DEPRECATED);
429+
430+
class_exists( Fixtures\FinalConstant\OverrideFinalConstant81::class, true);
431+
432+
error_reporting($e);
433+
restore_error_handler();
434+
435+
$this->assertSame([
436+
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant\FinalConstantsInterface::OVERRIDDEN_FINAL_INTERFACE" constant is considered final. You should not override it in "Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant\OverrideFinalConstant81".',
437+
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant\FinalConstantsInterface2::OVERRIDDEN_FINAL_INTERFACE_2" constant is considered final. You should not override it in "Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant\OverrideFinalConstant81".',
438+
], $deprecations);
439+
}
403440
}
404441

405442
class ClassLoader
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant;
4+
5+
class FinalConstants extends FinalConstants2
6+
{
7+
/**
8+
* @final
9+
*/
10+
protected const OVERRIDDEN_FINAL_PARENT_CLASS = 'OVERRIDDEN_FINAL_PARENT_CLASS';
11+
12+
protected const OVERRIDDEN_NOT_FINAL_PARENT_CLASS = 'OVERRIDDEN_NOT_FINAL_PARENT_CLASS';
13+
14+
/**
15+
* @final
16+
*/
17+
public const NOT_OVERRIDDEN_FINAL_PARENT_CLASS = 'NOT_OVERRIDDEN_FINAL_PARENT_CLASS';
18+
19+
public const NOT_OVERRIDDEN_NOT_FINAL_PARENT_CLASS = 'NOT_OVERRIDDEN_NOT_FINAL_PARENT_CLASS';
20+
21+
private const FOO = 'FOO';
22+
}
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant;
4+
5+
class FinalConstants2 {
6+
/**
7+
* @final
8+
*/
9+
public const OVERRIDDEN_FINAL_PARENT_PARENT_CLASS = 'OVERRIDDEN_FINAL_PARENT_PARENT_CLASS';
10+
11+
public const OVERRIDDEN_NOT_FINAL_PARENT_PARENT_CLASS = 'OVERRIDDEN_NOT_FINAL_PARENT_PARENT_CLASS';
12+
13+
/**
14+
* @final
15+
*/
16+
public const NOT_OVERRIDDEN_FINAL_PARENT_PARENT_CLASS = 'NOT_OVERRIDDEN_FINAL_PARENT_PARENT_CLASS';
17+
18+
public const NOT_OVERRIDDEN_NOT_FINAL_PARENT_PARENT_CLASS = 'NOT_OVERRIDDEN_NOT_FINAL_PARENT_PARENT_CLASS';
19+
}
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant;
4+
5+
interface FinalConstantsInterface
6+
{
7+
/**
8+
* @final
9+
*/
10+
public const OVERRIDDEN_FINAL_INTERFACE = 'OVERRIDDEN_FINAL_INTERFACE';
11+
12+
public const OVERRIDDEN_NOT_FINAL_INTERFACE = 'OVERRIDDEN_NOT_FINAL_INTERFACE';
13+
14+
/**
15+
* @final
16+
*/
17+
public const NOT_OVERRIDDEN_FINAL_INTERFACE = 'NOT_OVERRIDDEN_FINAL_INTERFACE';
18+
19+
public const NOT_OVERRIDDEN_NOT_FINAL_INTERFACE = 'NOT_OVERRIDDEN_NOT_FINAL_INTERFACE';
20+
}
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant;
4+
5+
interface FinalConstantsInterface2 extends FinalConstantsInterface
6+
{
7+
/**
8+
* @final for whatever reason
9+
*/
10+
public const OVERRIDDEN_FINAL_INTERFACE_2 = 'OVERRIDDEN_FINAL_INTERFACE_2';
11+
12+
public const OVERRIDDEN_NOT_FINAL_INTERFACE_2 = 'OVERRIDDEN_NOT_FINAL_INTERFACE_2';
13+
14+
/**
15+
* @final
16+
*/
17+
public const NOT_OVERRIDDEN_FINAL_INTERFACE_2 = 'NOT_OVERRIDDEN_FINAL_INTERFACE_2';
18+
19+
public const NOT_OVERRIDDEN_NOT_FINAL_INTERFACE_2 = 'NOT_OVERRIDDEN_NOT_FINAL_INTERFACE_2';
20+
}
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant;
4+
5+
class OverrideFinalConstant extends FinalConstants
6+
{
7+
public const FOO = 'FOO';
8+
9+
protected const OVERRIDDEN_FINAL_PARENT_CLASS = 'O_OVERRIDDEN_FINAL_PARENT_CLASS';
10+
11+
protected const OVERRIDDEN_NOT_FINAL_PARENT_CLASS = 'O_OVERRIDDEN_NOT_FINAL_PARENT_CLASS';
12+
13+
public const OVERRIDDEN_FINAL_PARENT_PARENT_CLASS = 'O_OVERRIDDEN_FINAL_PARENT_PARENT_CLASS';
14+
15+
public const OVERRIDDEN_NOT_FINAL_PARENT_PARENT_CLASS = 'O_OVERRIDDEN_NOT_FINAL_PARENT_PARENT_CLASS';
16+
17+
private const CCC = 'CCC';
18+
}
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Symfony\Component\ErrorHandler\Tests\Fixtures\FinalConstant;
4+
5+
class OverrideFinalConstant81 implements FinalConstantsInterface2
6+
{
7+
public const FOO = 'FOO';
8+
9+
public const OVERRIDDEN_FINAL_INTERFACE = 'O_OVERRIDDEN_FINAL_INTERFACE';
10+
11+
public const OVERRIDDEN_NOT_FINAL_INTERFACE = 'O_OVERRIDDEN_NOT_FINAL_INTERFACE';
12+
13+
public const OVERRIDDEN_FINAL_INTERFACE_2 = 'O_OVERRIDDEN_FINAL_INTERFACE_2';
14+
15+
public const OVERRIDDEN_NOT_FINAL_INTERFACE_2 = 'O_OVERRIDDEN_NOT_FINAL_INTERFACE_2';
16+
17+
private const CCC = 'CCC';
18+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.