Skip to content

Commit

Permalink
Merge pull request #133 from goaop/feature/4.0-cleanup
Browse files Browse the repository at this point in the history
New 4.0 version implementation for PHP>=8.2
  • Loading branch information
lisachenko authored Mar 18, 2024
2 parents 8fc097d + 3f6af6f commit e7e6192
Show file tree
Hide file tree
Showing 64 changed files with 2,980 additions and 1,856 deletions.
1 change: 1 addition & 0 deletions .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
- "highest"
php-version:
- "8.2"
- "8.3"
operating-system:
- "ubuntu-latest"

Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2015-2020 Alexander Lisachenko
Copyright (c) 2015-2024 Alexander Lisachenko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
},
"require": {
"php": ">=8.2",
"nikic/php-parser": "^4.0"
"nikic/php-parser": "^5.0"
},
"require-dev": {
"phpunit/phpunit": "^10.5.8",
"tracy/tracy": "^2.10"
"tracy/tracy": "^2.10",
"rector/rector": "^1.0",
"rector/rector-php-parser": "^0.14.0"
},
"extra": {
"branch-alias": {
Expand Down
3 changes: 3 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@
<directory>./src/</directory>
</include>
</source>
<php>
<ini name="memory_limit" value="512M" />
</php>
</phpunit>
32 changes: 32 additions & 0 deletions rector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessParamTagRector;
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessReturnTagRector;
use Rector\Php71\Rector\ClassConst\PublicConstantVisibilityRector;
use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector;
use Rector\PhpParser\Set\PhpParserSetList;
use Rector\PHPUnit\Set\PHPUnitSetList;
use Rector\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector;

return RectorConfig::configure()
->withPaths([
__DIR__ . '/src',
__DIR__ . '/tests',
])
// uncomment to reach your current PHP version
// ->withPhpSets()
->withRules([
AddVoidReturnTypeWhereNoReturnRector::class,
RemoveUselessParamTagRector::class,
RemoveUselessReturnTagRector::class,
PublicConstantVisibilityRector::class,
ClosureToArrowFunctionRector::class,
])
->withSets([
PHPUnitSetList::ANNOTATIONS_TO_ATTRIBUTES,
PHPUnitSetList::PHPUNIT_CODE_QUALITY,
PhpParserSetList::PHP_PARSER_50
]);
5 changes: 2 additions & 3 deletions src/Locator/CallableLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

/**
* Locator, that can find a file for the given class name by asking composer
* @see \Go\ParserReflection\Locator\CallableLocatorTest
*/
class CallableLocator implements LocatorInterface
{
Expand All @@ -33,10 +34,8 @@ public function __construct(callable $callable)
* Returns a path to the file for given class name
*
* @param string $className Name of the class
*
* @return string|false Path to the file with given class or false if not found
*/
public function locateClass(string $className)
public function locateClass(string $className): false|string
{
return call_user_func($this->callable, ltrim($className, '\\'));
}
Expand Down
7 changes: 3 additions & 4 deletions src/Locator/ComposerLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

/**
* Locator, that can find a file for the given class name by asking composer
* @see \Go\ParserReflection\Locator\ComposerLocatorTest
*/
class ComposerLocator implements LocatorInterface
{
Expand Down Expand Up @@ -48,10 +49,8 @@ public function __construct(ClassLoader $composerLoader = null)
* Returns a path to the file for given class name
*
* @param string $className Name of the class
*
* @return string|false Path to the file with given class or false if not found
*/
public function locateClass(string $className)
**/
public function locateClass(string $className): false|string
{
$filePath = $this->loader->findFile(ltrim($className, '\\'));
if (!empty($filePath)) {
Expand Down
4 changes: 1 addition & 3 deletions src/LocatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ interface LocatorInterface
* Returns a path to the file for given class name
*
* @param string $className Name of the class (with or without leading '\' FQCN)
*
* @return string|false Path to the file with given class or false if not found
*/
public function locateClass(string $className);
public function locateClass(string $className): false|string;
}
5 changes: 2 additions & 3 deletions src/NodeVisitor/GeneratorDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@
namespace Go\ParserReflection\NodeVisitor;

use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;

/**
* Visitor to check if the method body
*/
class GeneratorDetector extends NodeVisitorAbstract
{
private $isGenerator = false;
private bool $isGenerator = false;

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

if ($node instanceof Node\Expr\Yield_ || $node instanceof Node\Expr\YieldFrom) {
Expand Down
13 changes: 5 additions & 8 deletions src/NodeVisitor/StaticVariablesCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@

namespace Go\ParserReflection\NodeVisitor;

use Go\ParserReflection\ValueResolver\NodeExpressionResolver;
use Go\ParserReflection\Resolver\NodeExpressionResolver;
use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;

/**
Expand All @@ -24,19 +23,17 @@ class StaticVariablesCollector extends NodeVisitorAbstract
{
/**
* Reflection context, eg. ReflectionClass, ReflectionMethod, etc
*
* @var mixed
*/
private $context;
private mixed $context;

private $staticVariables = [];
private array $staticVariables = [];

/**
* Default constructor
*
* @param mixed $context Reflection context, eg. ReflectionClass, ReflectionMethod, etc
*/
public function __construct($context)
public function __construct(mixed $context)
{
$this->context = $context;
}
Expand All @@ -48,7 +45,7 @@ public function enterNode(Node $node)
{
// There may be internal closures, we do not need to look at them
if ($node instanceof Node\Expr\Closure) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
return self::DONT_TRAVERSE_CHILDREN;
}

if ($node instanceof Node\Stmt\Static_) {
Expand Down
10 changes: 5 additions & 5 deletions src/ReflectionAttribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@

namespace Go\ParserReflection;

use Go\ParserReflection\ValueResolver\NodeExpressionResolver;
use ReflectionAttribute as BaseReflectionAttribute;
use Go\ParserReflection\Resolver\NodeExpressionResolver;
use PhpParser\Node;
use PhpParser\Node\Param;
use PhpParser\Node\PropertyItem;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassConst;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\PropertyProperty;
use ReflectionAttribute as BaseReflectionAttribute;

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

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

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

Expand Down
32 changes: 22 additions & 10 deletions src/ReflectionClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
use Go\ParserReflection\Traits\ReflectionClassLikeTrait;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Enum_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\TraitUse;
use ReflectionClass as InternalReflectionClass;

/**
* AST-based reflection class
* @see \Go\ParserReflection\ReflectionClassTest
*/
class ReflectionClass extends InternalReflectionClass
{
Expand All @@ -33,10 +35,10 @@ class ReflectionClass extends InternalReflectionClass
/**
* Initializes reflection instance
*
* @param string|object $argument Class name or instance of object
* @param object|string $argument Class name or instance of object
* @param ?ClassLike $classLikeNode AST node for class
*/
public function __construct($argument, ClassLike $classLikeNode = null)
public function __construct(object|string $argument, ?ClassLike $classLikeNode = null)
{
$fullClassName = is_object($argument) ? get_class($argument) : ltrim($argument, '\\');
$namespaceParts = explode('\\', $fullClassName);
Expand All @@ -60,9 +62,11 @@ public static function collectInterfacesFromClassNode(ClassLike $classLikeNode):

$isInterface = $classLikeNode instanceof Interface_;
$interfaceField = $isInterface ? 'extends' : 'implements';
$hasInterfaces = in_array($interfaceField, $classLikeNode->getSubNodeNames(), true);
$implementsList = $hasInterfaces ? $classLikeNode->$interfaceField : [];
if ($implementsList) {

$hasExplicitInterfaces = in_array($interfaceField, $classLikeNode->getSubNodeNames(), true);
$implementsList = $hasExplicitInterfaces ? $classLikeNode->$interfaceField : [];

if (count($implementsList) > 0) {
foreach ($implementsList as $implementNode) {
if ($implementNode instanceof FullyQualified) {
$implementName = $implementNode->toString();
Expand All @@ -75,6 +79,17 @@ public static function collectInterfacesFromClassNode(ClassLike $classLikeNode):
}
}

// All Enum classes has implicit interface(s) added by PHP
if ($classLikeNode instanceof Enum_) {
// @see https://php.watch/versions/8.1/enums#enum-BackedEnum
$interfacesToAdd = isset($classLikeNode->scalarType)
? [\UnitEnum::class, \BackedEnum::class] // PHP Uses exactly this order, not reversed by parent!
: [\UnitEnum::class];
foreach ($interfacesToAdd as $interfaceToAdd) {
$interfaces[$interfaceToAdd] = new parent($interfaceToAdd);
}
}

return $interfaces;
}

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

/**
* Implementation of internal reflection initialization
*
* @return void
*/
protected function __initialize(): void
{
Expand All @@ -140,12 +153,11 @@ protected function __initialize(): void
/**
* Create a ReflectionClass for a given class name.
*
* @param string $className
* The name of the class to create a reflection for.
* @param string $className The name of the class to create a reflection for.
*
* @return InternalReflectionClass The appropriate reflection object.
*/
protected function createReflectionForClass(string $className)
protected function createReflectionForClass(string $className): InternalReflectionClass
{
return class_exists($className, false) ? new parent($className) : new static($className);
}
Expand Down
Loading

0 comments on commit e7e6192

Please sign in to comment.