alekitto / class-finder

Utility classes to help discover other classes/namespaces
https://alekitto.github.io/class-finder/
MIT License
27 stars 6 forks source link

Cannot find classes on package that have `class_exists` usage #18

Closed llaville closed 6 months ago

llaville commented 6 months ago

Hello @alekitto

Related to issue #13, I've found another usage of class_exists package that lead to a Fatal error.

Here are the details of test to reproduce error :

tree --filelimit 5
.
├── composer.json
├── composer.lock
├── find.php
├── otherProject
│   ├── composer.json
│   ├── composer.lock
│   └── vendor
│       ├── autoload.php
│       ├── bin
│       │   └── php-parse
│       ├── composer  [11 entries exceeds filelimit, not opening dir]
│       └── nikic
│           └── php-parser
│               ├── bin
│               │   └── php-parse
│               ├── composer.json
│               ├── lib
│               │   └── PhpParser  [37 entries exceeds filelimit, not opening dir]
│               ├── LICENSE
│               └── README.md
└── vendor
    ├── autoload.php
    ├── composer  [12 entries exceeds filelimit, not opening dir]
    ├── kcs
    │   └── class-finder  [9 entries exceeds filelimit, not opening dir]
    └── thecodingmachine
        └── safe  [7 entries exceeds filelimit, not opening dir]

16 directories, 12 files

The main (project) composer.json file has following contents :

{
    "require": {
        "kcs/class-finder": "^0.4.0"
    }
}

The secondary (project) otherProject/composer.json file has following contents :

{
    "require": {
        "nikic/php-parser": "^4.18 || ^5.0"
    }
}

The script to find classes is find.php with such contents :

<?php

require_once 'vendor/autoload.php';

$otherProjectClassLoader = require __DIR__ . '/otherProject/vendor/autoload.php';

use Kcs\ClassFinder\Finder\ComposerFinder;

$finder = new ComposerFinder($otherProjectClassLoader);

$count = 0;
foreach ($finder as $className => $reflector) {
    printf('- %s ' . PHP_EOL, $className);
    ++$count;
}
printf('> found %d class(es)' . PHP_EOL, $count);

And now results with Fatal error, due to class_exists usage on nikic/php-parser package.

find script results ```text - Composer\InstalledVersions - PhpParser\Builder\Param - PhpParser\Builder\Namespace_ - PhpParser\Builder\EnumCase - PhpParser\Builder\Declaration - PhpParser\Builder\ClassConst - PhpParser\Builder\Trait_ - PhpParser\Builder\TraitUseAdaptation - PhpParser\Builder\TraitUse - PhpParser\Builder\Use_ - PhpParser\Builder\FunctionLike - PhpParser\Builder\Interface_ - PhpParser\Builder\Property - PhpParser\Builder\Enum_ - PhpParser\Builder\Function_ - PhpParser\Builder\Method - PhpParser\Builder\Class_ - PhpParser\Builder - PhpParser\BuilderFactory - PhpParser\BuilderHelpers - PhpParser\Comment\Doc - PhpParser\Comment - PhpParser\ConstExprEvaluationException - PhpParser\ConstExprEvaluator - PhpParser\Error - PhpParser\ErrorHandler\Throwing - PhpParser\ErrorHandler\Collecting - PhpParser\ErrorHandler - PhpParser\Internal\Differ - PhpParser\Internal\TokenStream - PhpParser\Internal\PrintableNewAnonClassNode - PhpParser\Internal\TokenPolyfill - PhpParser\Internal\DiffElem - PhpParser\JsonDecoder - PhpParser\Lexer\TokenEmulator\ReadonlyFunctionTokenEmulator - PhpParser\Lexer\TokenEmulator\KeywordEmulator - PhpParser\Lexer\TokenEmulator\ReverseEmulator - PhpParser\Lexer\TokenEmulator\MatchTokenEmulator - PhpParser\Lexer\TokenEmulator\TokenEmulator - PhpParser\Lexer\TokenEmulator\EnumTokenEmulator - PhpParser\Lexer\TokenEmulator\ReadonlyTokenEmulator - PhpParser\Lexer\TokenEmulator\NullsafeTokenEmulator - PhpParser\Lexer\TokenEmulator\AttributeEmulator - PhpParser\Lexer\TokenEmulator\ExplicitOctalEmulator - PhpParser\Lexer\Emulative - PhpParser\Lexer - PhpParser\Modifiers - PhpParser\NameContext - PhpParser\Node\Attribute - PhpParser\Node\Stmt - PhpParser\Node\Param - PhpParser\Node\Identifier - PhpParser\Node\DeclareItem - PhpParser\Node\Arg - PhpParser\Node\IntersectionType - PhpParser\Node\Name - PhpParser\Node\AttributeGroup - PhpParser\Node\UnionType - PhpParser\Node\NullableType - PhpParser\Node\Name\FullyQualified - PhpParser\Node\Name\Relative - PhpParser\Node\Stmt\Foreach_ - PhpParser\Node\Stmt\Return_ - PhpParser\Node\Stmt\Namespace_ - PhpParser\Node\Stmt\ClassMethod - PhpParser\Node\Stmt\Break_ - PhpParser\Node\Stmt\Nop - PhpParser\Node\Stmt\EnumCase - PhpParser\Node\Stmt\Expression - PhpParser\Node\Stmt\HaltCompiler - PhpParser\Node\Stmt\ClassConst - PhpParser\Node\Stmt\Label - PhpParser\Node\Stmt\Continue_ - PhpParser\Node\Stmt\Trait_ - PhpParser\Node\Stmt\Switch_ - PhpParser\Node\Stmt\Finally_ - PhpParser\Node\Stmt\Unset_ - PhpParser\Node\Stmt\Do_ - PhpParser\Node\Stmt\GroupUse - PhpParser\Node\Stmt\Catch_ - PhpParser\Node\Stmt\Case_ - PhpParser\Node\Stmt\TraitUseAdaptation - PhpParser\Node\Stmt\TraitUse - PhpParser\Node\Stmt\PropertyProperty - PhpParser\Node\Stmt\ElseIf_ - PhpParser\Node\Stmt\While_ - PhpParser\Node\Stmt\For_ - PhpParser\Node\Stmt\Use_ - PhpParser\Node\Stmt\Echo_ Fatal error: Cannot declare class PhpParser\Node\DeclareItem, because the name is already in use in /shared/backups/github/class-finder-issues/otherProject/vendor/nikic/php-parser/lib/PhpParser/Node/DeclareItem.php on line 8 Call Stack: 0.0002 1966048 1. {main}() /shared/backups/github/class-finder-issues/find.php:0 0.0389 5952448 2. Kcs\ClassFinder\Iterator\ClassIterator->next() /shared/backups/github/class-finder-issues/find.php:19 0.0389 5952448 3. Generator->next() /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/ClassIterator.php:60 0.0389 5952448 4. Kcs\ClassFinder\Iterator\ClassIterator->next() /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/ComposerIterator.php:81 0.0389 5952448 5. Generator->next() /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/ClassIterator.php:60 0.0389 5952448 6. Kcs\ClassFinder\Iterator\Psr4Iterator->getGenerator() /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/ClassIterator.php:60 0.0389 5952512 7. Kcs\ClassFinder\Iterator\{closure:/shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/Psr4Iterator.php:59-61}($path = '/shared/backups/github/class-finder-issues/otherProject/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php') /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/Psr4Iterator.php:96 0.0390 5953512 8. include_once('/shared/backups/github/class-finder-issues/otherProject/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php') /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/Psr4Iterator.php:60 0.0391 5957784 9. require('/shared/backups/github/class-finder-issues/otherProject/vendor/nikic/php-parser/lib/PhpParser/Node/DeclareItem.php') /shared/backups/github/class-finder-issues/otherProject/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php:3 ```
alekitto commented 6 months ago

Can you please test it against dev-master?

llaville commented 6 months ago

ok with - Upgrading kcs/class-finder (0.4.0 => dev-master 29131dc): Extracting archive all works fine !

llaville commented 6 months ago

BTW, it won't work (or as previous with Fatal error) if you disable autoloading feature (enabled by default in ComposerFinder)

$finder = new ComposerFinder($otherProjectClassLoader);
$finder->useAutoloading(false);
alekitto commented 6 months ago

BTW, it won't work (or as previous with Fatal error) if you disable autoloading feature (enabled by default in ComposerFinder)

Yes, this is expected, as php-parser has a class_alias BC layer. Needs to be ignored if autoloading is disabled.