Skip to content

Commit 01eb32c

Browse files
committed
resolve class constant types when patching return types
1 parent 1d8d1c3 commit 01eb32c

File tree

6 files changed

+91
-1
lines changed

6 files changed

+91
-1
lines changed

src/Symfony/Component/ErrorHandler/DebugClassLoader.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,30 @@ private function setReturnType(string $types, string $class, string $method, str
849849
$docTypes = [];
850850

851851
foreach ($typesMap as $n => $t) {
852+
if (str_contains($n, '::')) {
853+
[$definingClass, $constantName] = explode('::', $n, 2);
854+
$definingClass = match ($definingClass) {
855+
'self', 'static', 'parent' => $class,
856+
default => $definingClass,
857+
};
858+
859+
if (!\defined($definingClass.'::'.$constantName)) {
860+
return;
861+
}
862+
863+
$constant = new \ReflectionClassConstant($definingClass, $constantName);
864+
865+
if (\PHP_VERSION_ID >= 80300 && $constantType = $constant->getType()) {
866+
if ($constantType instanceof \ReflectionNamedType) {
867+
$n = $constantType->getName();
868+
} else {
869+
return;
870+
}
871+
} else {
872+
$n = \gettype($constant->getValue());
873+
}
874+
}
875+
852876
if ('null' === $n) {
853877
$nullable = true;
854878
continue;
@@ -872,7 +896,7 @@ private function setReturnType(string $types, string $class, string $method, str
872896
continue;
873897
}
874898

875-
if (!isset($phpTypes[''])) {
899+
if (!isset($phpTypes['']) && !\in_array($n, $phpTypes, true)) {
876900
$phpTypes[] = $n;
877901
}
878902
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,26 @@ class_exists('Test\\'.ReturnType::class, true);
401401
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::true()" might add "true" 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.',
402402
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::never()" might add "never" 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.',
403403
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::null()" might add "null" 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.',
404+
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::classConstant()" might add "string" 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.',
405+
], $deprecations);
406+
}
407+
408+
/**
409+
* @requires PHP >= 8.3
410+
*/
411+
public function testReturnTypePhp83()
412+
{
413+
$deprecations = [];
414+
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
415+
$e = error_reporting(E_USER_DEPRECATED);
416+
417+
class_exists('Test\\'.ReturnTypePhp83::class, true);
418+
419+
error_reporting($e);
420+
restore_error_handler();
421+
422+
$this->assertSame([
423+
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParentPhp83::classConstantWithType()" might add "string" as a native return type declaration in the future. Do the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnTypePhp83" now to avoid errors or add an explicit @return annotation to suppress this message.',
404424
], $deprecations);
405425
}
406426

@@ -542,6 +562,8 @@ public function ownAbstractBaseMethod() { }
542562
}');
543563
} elseif ('Test\\'.ReturnType::class === $class) {
544564
return $fixtureDir.\DIRECTORY_SEPARATOR.'ReturnType.php';
565+
} elseif ('Test\\'.ReturnTypePhp83::class === $class) {
566+
return $fixtureDir.\DIRECTORY_SEPARATOR.'ReturnTypePhp83.php';
545567
} elseif ('Test\\'.Fixtures\OutsideInterface::class === $class) {
546568
return $fixtureDir.\DIRECTORY_SEPARATOR.'OutsideInterface.php';
547569
} elseif ('Test\\'.OverrideOutsideFinalProperty::class === $class) {

src/Symfony/Component/ErrorHandler/Tests/Fixtures/ReturnType.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,5 @@ public function true() { }
5151
public function never() { }
5252
public function null() { }
5353
public function outsideMethod() { }
54+
public function classConstant() { }
5455
}

src/Symfony/Component/ErrorHandler/Tests/Fixtures/ReturnTypeParent.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
abstract class ReturnTypeParent extends ReturnTypeGrandParent implements ReturnTypeParentInterface
66
{
7+
const FOO = 'foo';
8+
79
/**
810
* @return void
911
*/
@@ -254,4 +256,11 @@ public function null()
254256
public function notExtended()
255257
{
256258
}
259+
260+
/**
261+
* @return self::FOO
262+
*/
263+
public function classConstant()
264+
{
265+
}
257266
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Symfony\Component\ErrorHandler\Tests\Fixtures;
4+
5+
abstract class ReturnTypeParentPhp83
6+
{
7+
const string FOO = 'foo';
8+
const string|int BAR = 'bar';
9+
10+
/**
11+
* @return self::FOO
12+
*/
13+
public function classConstantWithType()
14+
{
15+
}
16+
17+
/**
18+
* @return self::BAR
19+
*/
20+
public function classConstantWithUnionType()
21+
{
22+
}
23+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Test\Symfony\Component\ErrorHandler\Tests;
4+
5+
use Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParentPhp83;
6+
7+
class ReturnTypePhp83 extends ReturnTypeParentPhp83
8+
{
9+
public function classConstantWithType() { }
10+
public function classConstantWithUnionType() { }
11+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy