Skip to content

Commit e7e6192

Browse files
authored
Merge pull request #133 from goaop/feature/4.0-cleanup
New 4.0 version implementation for PHP>=8.2
2 parents 8fc097d + 3f6af6f commit e7e6192

File tree

64 files changed

+2980
-1856
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2980
-1856
lines changed

.github/workflows/phpunit.yml

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ jobs:
1717
- "highest"
1818
php-version:
1919
- "8.2"
20+
- "8.3"
2021
operating-system:
2122
- "ubuntu-latest"
2223

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2015-2020 Alexander Lisachenko
1+
Copyright (c) 2015-2024 Alexander Lisachenko
22

33
Permission is hereby granted, free of charge, to any person obtaining a copy
44
of this software and associated documentation files (the "Software"), to deal

composer.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@
2323
},
2424
"require": {
2525
"php": ">=8.2",
26-
"nikic/php-parser": "^4.0"
26+
"nikic/php-parser": "^5.0"
2727
},
2828
"require-dev": {
2929
"phpunit/phpunit": "^10.5.8",
30-
"tracy/tracy": "^2.10"
30+
"tracy/tracy": "^2.10",
31+
"rector/rector": "^1.0",
32+
"rector/rector-php-parser": "^0.14.0"
3133
},
3234
"extra": {
3335
"branch-alias": {

phpunit.xml.dist

+3
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@
1010
<directory>./src/</directory>
1111
</include>
1212
</source>
13+
<php>
14+
<ini name="memory_limit" value="512M" />
15+
</php>
1316
</phpunit>

rector.php

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessParamTagRector;
7+
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessReturnTagRector;
8+
use Rector\Php71\Rector\ClassConst\PublicConstantVisibilityRector;
9+
use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector;
10+
use Rector\PhpParser\Set\PhpParserSetList;
11+
use Rector\PHPUnit\Set\PHPUnitSetList;
12+
use Rector\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector;
13+
14+
return RectorConfig::configure()
15+
->withPaths([
16+
__DIR__ . '/src',
17+
__DIR__ . '/tests',
18+
])
19+
// uncomment to reach your current PHP version
20+
// ->withPhpSets()
21+
->withRules([
22+
AddVoidReturnTypeWhereNoReturnRector::class,
23+
RemoveUselessParamTagRector::class,
24+
RemoveUselessReturnTagRector::class,
25+
PublicConstantVisibilityRector::class,
26+
ClosureToArrowFunctionRector::class,
27+
])
28+
->withSets([
29+
PHPUnitSetList::ANNOTATIONS_TO_ATTRIBUTES,
30+
PHPUnitSetList::PHPUNIT_CODE_QUALITY,
31+
PhpParserSetList::PHP_PARSER_50
32+
]);

src/Locator/CallableLocator.php

+2-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
/**
1818
* Locator, that can find a file for the given class name by asking composer
19+
* @see \Go\ParserReflection\Locator\CallableLocatorTest
1920
*/
2021
class CallableLocator implements LocatorInterface
2122
{
@@ -33,10 +34,8 @@ public function __construct(callable $callable)
3334
* Returns a path to the file for given class name
3435
*
3536
* @param string $className Name of the class
36-
*
37-
* @return string|false Path to the file with given class or false if not found
3837
*/
39-
public function locateClass(string $className)
38+
public function locateClass(string $className): false|string
4039
{
4140
return call_user_func($this->callable, ltrim($className, '\\'));
4241
}

src/Locator/ComposerLocator.php

+3-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
/**
2121
* Locator, that can find a file for the given class name by asking composer
22+
* @see \Go\ParserReflection\Locator\ComposerLocatorTest
2223
*/
2324
class ComposerLocator implements LocatorInterface
2425
{
@@ -48,10 +49,8 @@ public function __construct(ClassLoader $composerLoader = null)
4849
* Returns a path to the file for given class name
4950
*
5051
* @param string $className Name of the class
51-
*
52-
* @return string|false Path to the file with given class or false if not found
53-
*/
54-
public function locateClass(string $className)
52+
**/
53+
public function locateClass(string $className): false|string
5554
{
5655
$filePath = $this->loader->findFile(ltrim($className, '\\'));
5756
if (!empty($filePath)) {

src/LocatorInterface.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ interface LocatorInterface
2121
* Returns a path to the file for given class name
2222
*
2323
* @param string $className Name of the class (with or without leading '\' FQCN)
24-
*
25-
* @return string|false Path to the file with given class or false if not found
2624
*/
27-
public function locateClass(string $className);
25+
public function locateClass(string $className): false|string;
2826
}

src/NodeVisitor/GeneratorDetector.php

+2-3
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@
1313
namespace Go\ParserReflection\NodeVisitor;
1414

1515
use PhpParser\Node;
16-
use PhpParser\NodeTraverser;
1716
use PhpParser\NodeVisitorAbstract;
1817

1918
/**
2019
* Visitor to check if the method body
2120
*/
2221
class GeneratorDetector extends NodeVisitorAbstract
2322
{
24-
private $isGenerator = false;
23+
private bool $isGenerator = false;
2524

2625
/**
2726
* {@inheritDoc}
@@ -30,7 +29,7 @@ public function enterNode(Node $node)
3029
{
3130
// There may be internal generators in closures, we do not need to look at them
3231
if ($node instanceof Node\Expr\Closure) {
33-
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
32+
return self::DONT_TRAVERSE_CHILDREN;
3433
}
3534

3635
if ($node instanceof Node\Expr\Yield_ || $node instanceof Node\Expr\YieldFrom) {

src/NodeVisitor/StaticVariablesCollector.php

+5-8
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212

1313
namespace Go\ParserReflection\NodeVisitor;
1414

15-
use Go\ParserReflection\ValueResolver\NodeExpressionResolver;
15+
use Go\ParserReflection\Resolver\NodeExpressionResolver;
1616
use PhpParser\Node;
17-
use PhpParser\NodeTraverser;
1817
use PhpParser\NodeVisitorAbstract;
1918

2019
/**
@@ -24,19 +23,17 @@ class StaticVariablesCollector extends NodeVisitorAbstract
2423
{
2524
/**
2625
* Reflection context, eg. ReflectionClass, ReflectionMethod, etc
27-
*
28-
* @var mixed
2926
*/
30-
private $context;
27+
private mixed $context;
3128

32-
private $staticVariables = [];
29+
private array $staticVariables = [];
3330

3431
/**
3532
* Default constructor
3633
*
3734
* @param mixed $context Reflection context, eg. ReflectionClass, ReflectionMethod, etc
3835
*/
39-
public function __construct($context)
36+
public function __construct(mixed $context)
4037
{
4138
$this->context = $context;
4239
}
@@ -48,7 +45,7 @@ public function enterNode(Node $node)
4845
{
4946
// There may be internal closures, we do not need to look at them
5047
if ($node instanceof Node\Expr\Closure) {
51-
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
48+
return self::DONT_TRAVERSE_CHILDREN;
5249
}
5350

5451
if ($node instanceof Node\Stmt\Static_) {

src/ReflectionAttribute.php

+5-5
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@
1212

1313
namespace Go\ParserReflection;
1414

15-
use Go\ParserReflection\ValueResolver\NodeExpressionResolver;
16-
use ReflectionAttribute as BaseReflectionAttribute;
15+
use Go\ParserReflection\Resolver\NodeExpressionResolver;
1716
use PhpParser\Node;
1817
use PhpParser\Node\Param;
18+
use PhpParser\Node\PropertyItem;
1919
use PhpParser\Node\Stmt\Class_;
2020
use PhpParser\Node\Stmt\ClassConst;
2121
use PhpParser\Node\Stmt\ClassMethod;
2222
use PhpParser\Node\Stmt\Function_;
2323
use PhpParser\Node\Stmt\Property;
24-
use PhpParser\Node\Stmt\PropertyProperty;
24+
use ReflectionAttribute as BaseReflectionAttribute;
2525

2626
/**
2727
* ref original usage https://3v4l.org/duaQI
@@ -38,11 +38,11 @@ public function __construct(
3838

3939
public function getNode(): Node\Attribute
4040
{
41-
/** @var Class_|ClassMethod|PropertyProperty|ClassConst|Function_|Param $node */
41+
/** @var Class_|ClassMethod|PropertyItem|ClassConst|Function_|Param $node */
4242
$node = $this->reflector->getNode();
4343

4444
// attrGroups only exists in Property Stmt
45-
if ($node instanceof PropertyProperty) {
45+
if ($node instanceof PropertyItem) {
4646
$node = $this->reflector->getTypeNode();
4747
}
4848

src/ReflectionClass.php

+22-10
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717
use Go\ParserReflection\Traits\ReflectionClassLikeTrait;
1818
use PhpParser\Node\Name\FullyQualified;
1919
use PhpParser\Node\Stmt\ClassLike;
20+
use PhpParser\Node\Stmt\Enum_;
2021
use PhpParser\Node\Stmt\Interface_;
2122
use PhpParser\Node\Stmt\TraitUse;
2223
use ReflectionClass as InternalReflectionClass;
2324

2425
/**
2526
* AST-based reflection class
27+
* @see \Go\ParserReflection\ReflectionClassTest
2628
*/
2729
class ReflectionClass extends InternalReflectionClass
2830
{
@@ -33,10 +35,10 @@ class ReflectionClass extends InternalReflectionClass
3335
/**
3436
* Initializes reflection instance
3537
*
36-
* @param string|object $argument Class name or instance of object
38+
* @param object|string $argument Class name or instance of object
3739
* @param ?ClassLike $classLikeNode AST node for class
3840
*/
39-
public function __construct($argument, ClassLike $classLikeNode = null)
41+
public function __construct(object|string $argument, ?ClassLike $classLikeNode = null)
4042
{
4143
$fullClassName = is_object($argument) ? get_class($argument) : ltrim($argument, '\\');
4244
$namespaceParts = explode('\\', $fullClassName);
@@ -60,9 +62,11 @@ public static function collectInterfacesFromClassNode(ClassLike $classLikeNode):
6062

6163
$isInterface = $classLikeNode instanceof Interface_;
6264
$interfaceField = $isInterface ? 'extends' : 'implements';
63-
$hasInterfaces = in_array($interfaceField, $classLikeNode->getSubNodeNames(), true);
64-
$implementsList = $hasInterfaces ? $classLikeNode->$interfaceField : [];
65-
if ($implementsList) {
65+
66+
$hasExplicitInterfaces = in_array($interfaceField, $classLikeNode->getSubNodeNames(), true);
67+
$implementsList = $hasExplicitInterfaces ? $classLikeNode->$interfaceField : [];
68+
69+
if (count($implementsList) > 0) {
6670
foreach ($implementsList as $implementNode) {
6771
if ($implementNode instanceof FullyQualified) {
6872
$implementName = $implementNode->toString();
@@ -75,6 +79,17 @@ public static function collectInterfacesFromClassNode(ClassLike $classLikeNode):
7579
}
7680
}
7781

82+
// All Enum classes has implicit interface(s) added by PHP
83+
if ($classLikeNode instanceof Enum_) {
84+
// @see https://php.watch/versions/8.1/enums#enum-BackedEnum
85+
$interfacesToAdd = isset($classLikeNode->scalarType)
86+
? [\UnitEnum::class, \BackedEnum::class] // PHP Uses exactly this order, not reversed by parent!
87+
: [\UnitEnum::class];
88+
foreach ($interfacesToAdd as $interfaceToAdd) {
89+
$interfaces[$interfaceToAdd] = new parent($interfaceToAdd);
90+
}
91+
}
92+
7893
return $interfaces;
7994
}
8095

@@ -129,8 +144,6 @@ public function getNode(): ?ClassLike
129144

130145
/**
131146
* Implementation of internal reflection initialization
132-
*
133-
* @return void
134147
*/
135148
protected function __initialize(): void
136149
{
@@ -140,12 +153,11 @@ protected function __initialize(): void
140153
/**
141154
* Create a ReflectionClass for a given class name.
142155
*
143-
* @param string $className
144-
* The name of the class to create a reflection for.
156+
* @param string $className The name of the class to create a reflection for.
145157
*
146158
* @return InternalReflectionClass The appropriate reflection object.
147159
*/
148-
protected function createReflectionForClass(string $className)
160+
protected function createReflectionForClass(string $className): InternalReflectionClass
149161
{
150162
return class_exists($className, false) ? new parent($className) : new static($className);
151163
}

0 commit comments

Comments
 (0)