Code Monkey home page Code Monkey logo

class-finder's Introduction

ClassFinder

Utility classes to help discover other classes/namespaces

Tests codecov


Installation

$ composer require kcs/class-finder

Usage

Finder helps you to discover classes into your project.

The most common way to discover is to use the provided ComposerFinder. This will search for classes using the auto-generated class loader from composer and resolving PSR-* namespaces accordingly.

Read more in the docs at https://alekitto.github.io/class-finder/

Basic usage

use Kcs\ClassFinder\Finder\ComposerFinder;

$finder = new ComposerFinder();
foreach ($finder as $className => $reflector) {
    // Do magic things...
}

Filtering

You can filter classes using the methods exposed by FinderInterface:

  • implementationOf(array $interfaces): Finds the classes that implements all the given interfaces. You can pass a single interface as string.
  • subclassOf(string $superClass): Finds all the classes that are subclasses of the given class.
  • annontatedBy(string $annotationClass): Finds all the classes that have the given annotation in the class docblock.
  • withAttribute(string $attributeClass): Finds all the classes that have the given attribute applied on the class (PHP >= 8.0) only.
  • in(array $dirs): Searches only in given directories.
  • inNamespace(array $namespaces): Searches only in given namespaces.
  • filter(callable $callback): Custom filtering callback.
  • pathFilter(callable $callback): Custom filtering callback for loading files.

License

This library is released under the MIT license.

Contributions

Contributions are always welcome. Please feel free to open a PR or file an issue.


Thank you for reading
A.

class-finder's People

Contributors

alekitto avatar alleknalle avatar lemorragia avatar massimilianobraglia avatar mpyw avatar szepeviktor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

class-finder's Issues

Loading files through autoloading - a possible solution

Hey @alekitto.

We stumbled upon your lib and wanted to use it to auto-discover classes in graphqlite. It generally works as expected, but isn't using autoloading. I understand why it's not using autoloading, but there are cases where autoloading is required for the class to function properly.

For example, we have a pre-8.0 enum implementation that uses a custom autoloader to call ::initialize() on enum classes being loaded, which initializes static properties of an enum.

So I dug a little bit deeper to see if there's anything that can be done on your end without Composer actually fixing composer/composer#6987.

What I thought was class-finder could check if the file that it's trying to load is one of the files from files section in composer.json. That's relatively trivial to do, because composer generates a vendor/composer/autoload_files.php file that just returns a list of all files to be loaded. Something like this:

$vendorDir = dirname(
    (new ReflectionClass(\Composer\Autoload\ClassLoader::class))->getFilename()
);
$autoloadedFiles = array_flip(
    require $vendorDir . '/autoload_files.php'
);

Then, when actually trying to load a class, instead of blindly using include_once, it could rely on autoloading to do so, given we first check if the file is contained in $autoloadedFiles:

if (isset($autoloadedFiles[$path]) {
    continue;
}

ErrorHandler::register();
try {
    if (!$this->exists($class)) {
        continue;
    } 
} catch (Throwable) { /** @phpstan-ignore-line */
    continue;
} finally {
    ErrorHandler::unregister();
}

yield $class => $this->reflectorFactory->reflect($class);

I understand this feels hacky. However, this solves a real world problem for us, and possibly more for others that are related to not using autoloading; and to be fair, this entire package is just a big hack around PHP's weird autoloading state.

I can PR these changes if that's something you'd accept.

FilteredComposerIterator doesn't accept "inside" of psr-4 directory

Problem

Assume that there is composer.json of Laravel project.

{
  "autoload": {
    "psr-4": {
      "App\\": "app/"
    }
  }
}

We need to find Eloquent Model classes inside of app/Models.

$finder = (new ComposerFinder())
    ->subclassOf(Model::class)
    ->in(base_path('app/Models'));

But it can't find any files.

Reason

Look at this class:

class-finder/FilteredComposerIterator.php at 60ba72245f9ae5eb0d670d49e3457150c47d19bc · alekitto/class-finder

If I fix the following line, it works as expected.

    private function validDir($path): bool
    {
        if (null === $this->dirs) {
            return true;
        }

        $path = PathNormalizer::resolvePath($path);
        foreach ($this->dirs as $dir) {
-           if (0 === \strpos($path, $dir)) {
+           if (0 === \strpos($dir, $path)) {
                return true;
            }
        }

        return false;
    }

Note that there are more similar statements in other filters that need to be fixed.

Incompatible with symfony/polyfill-php73

I like the concept of this package, but it's incompatible with some common packages like symfony/polyfill-php73 which define classes which conflict with PHP builtin classes:

iterator_to_array(new ComposerFinder);

PHP Fatal error: Cannot declare class JsonException, because the name is already in use in …/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php on line 12

Implements `Countable` interface on each Finder

Hello @alekitto

With my first report #13, I've found that ComposerFinder (but its always true to all other) is not yet able to count values of classes found (like Symfony Finder did it).

Compares both syntaxes

This one works with current version 0.4.0

$finder = new ComposerFinder();

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

But not yet this one

$finder = new ComposerFinder();

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

I suggest to fix at least the ComposerFinder code like this

final class ComposerFinder implements FinderInterface, \Countable
{


    public function count(): int
    {
        return \iterator_count($this->getIterator());
    }

}

And think about other finders, or have a common fix !

WDYT ?

Cannot find classes on package that have `class_exists` usage

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
- 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

Room for optimisation for ComposerFinder

Hello,

First, thank you for your awesome library. We have integrated it into our project, graphiqlite. However, we have encountered a performance regression issue as described in this issue.

Issue Description

In our use case, we utilize the inNamespace() method to filter the classes we need. From my understanding, ComposerFinder iterates through all available classes to check if any meet the specified condition. This approach results in performance bottlenecks.

Proposed Optimization

To optimize this process, I suggest that the filter should first check the namespaces of dependencies. If a dependency's namespace does not match the inNamespace condition, then the classes within that dependency should not be checked at all.

For example, if we need to build a condition for inNamespace('\Symfony') combined with implementationOf('CachingInterface'), it would be efficient to:

  1. Check only the dependencies within the \Symfony namespace.
  2. Filter out classes that do not implement CachingInterface.

This optimization should significantly reduce unnecessary checks and improve performance.

Would this proposed optimization make sense for you? I appreciate any feedback you can provide.

Thank you!

Separate `FileFinder` from the rest

Hey! Sorry for the long read: I wanted to provide some context for you to better understand the problem.

I have a package that depends on class-finder. It has multiple places where it iterates over FinderInterface. The namespaces are always the same, but it has to be iterated separately in multiple places.

For smaller projects, this is not a problem, as globbing and autoloading isn't that expensive for a couple hundred classes. In our case, the namespace we're scanning contains 10k+ classes, so the complete scan, along with autoloading and reflection, and done multiple times from different places, takes about 20sec.

Of course, the immediate solution is to simply cache the result of the FinderInterface. That works for a production environment, where files never change. For a development environment it's not that simple: usually only a few files change at a time, and doing a full scan every time is just not feasible. Which is why I'm instead implementing filemtime based caching: it uses class-finder's pathFilter feature to avoid autoloading/reflecting files that are known to not have changed.

The pathFilter solution works well if the FinderInteface is only iterated once. In our case, it's may be iterated over 6 times from different places and with different pathFilters. So a good optimization here would be to separate FileFinder from the rest of the code and allow specifying a custom instance of it when needed:

$cachedFileFinder = new CachedFileFinder(new GlobFileFinder(), new ArrayCache());

$finder1 = (new ComposerFinder())->useFileFinder($cachedFileFinder)->pathFilter(...);
$finder2 = (new ComposerFinder())->useFileFinder($cachedFileFinder)->pathFilter(...);

This way I would be able to cache the glob() that's happening inside the ComposerFinder.

In practise, this would mean adding a FileFinder interface and refactoring RecursiveIteratorTrait to use it. What do you think?

Fatal error when using `ComposerFinder` with the Symfony Cache Component

Hello @alekitto

I've just discover your package with recent major release 7.0 of GraphQLite

I've tried it on my new package still under development (and not yet published) that use the Symfony Cache Component, and got finding class issue.

Here is how to reproduce :

A simple composer.json with such contents

{
    "require": {
        "symfony/cache": "^6.4 || ^7.0",
        "kcs/class-finder": "^0.4.0"
    }
}

The script to reproduce error

<?php

require_once 'vendor/autoload.php';

use Kcs\ClassFinder\Finder\ComposerFinder;

$finder = new ComposerFinder();
//$finder->notPath('vendor/symfony/cache');

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

There is a strange entry - � in class list on results above

find results
- Composer\InstalledVersions
- Safe\DateTime
- Safe\DateTimeImmutable
- Safe\Exceptions\ApacheException
- Safe\Exceptions\ApcException
- Safe\Exceptions\ApcuException
- Safe\Exceptions\ArrayException
- Safe\Exceptions\Bzip2Exception
- Safe\Exceptions\CalendarException
- Safe\Exceptions\ClassobjException
- Safe\Exceptions\ComException
- Safe\Exceptions\CubridException
- Safe\Exceptions\CurlException
- Safe\Exceptions\DatetimeException
- Safe\Exceptions\DirException
- Safe\Exceptions\EioException
- Safe\Exceptions\ErrorfuncException
- Safe\Exceptions\ExecException
- Safe\Exceptions\FileinfoException
- Safe\Exceptions\FilesystemException
- Safe\Exceptions\FilterException
- Safe\Exceptions\FpmException
- Safe\Exceptions\FtpException
- Safe\Exceptions\FunchandException
- Safe\Exceptions\GettextException
- Safe\Exceptions\GmpException
- Safe\Exceptions\GnupgException
- Safe\Exceptions\HashException
- Safe\Exceptions\IbaseException
- Safe\Exceptions\IbmDb2Exception
- Safe\Exceptions\IconvException
- Safe\Exceptions\ImageException
- Safe\Exceptions\ImapException
- Safe\Exceptions\InfoException
- Safe\Exceptions\InotifyException
- Safe\Exceptions\JsonException
- Safe\Exceptions\LdapException
- Safe\Exceptions\LibeventException
- Safe\Exceptions\LibxmlException
- Safe\Exceptions\LzfException
- Safe\Exceptions\MailparseException
- Safe\Exceptions\MbstringException
- Safe\Exceptions\MiscException
- Safe\Exceptions\MssqlException
- Safe\Exceptions\MysqlException
- Safe\Exceptions\MysqliException
- Safe\Exceptions\NetworkException
- Safe\Exceptions\Oci8Exception
- Safe\Exceptions\OpcacheException
- Safe\Exceptions\OpensslException
- Safe\Exceptions\OutcontrolException
- Safe\Exceptions\PasswordException
- Safe\Exceptions\PcntlException
- Safe\Exceptions\PcreException
- Safe\Exceptions\PgsqlException
- Safe\Exceptions\PosixException
- Safe\Exceptions\PsException
- Safe\Exceptions\PspellException
- Safe\Exceptions\ReadlineException
- Safe\Exceptions\RpminfoException
- Safe\Exceptions\RrdException
- Safe\Exceptions\SafeExceptionInterface
- Safe\Exceptions\SemException
- Safe\Exceptions\SessionException
- Safe\Exceptions\ShmopException
- Safe\Exceptions\SimplexmlException
- Safe\Exceptions\SocketsException
- Safe\Exceptions\SodiumException
- Safe\Exceptions\SolrException
- Safe\Exceptions\SplException
- Safe\Exceptions\SqlsrvException
- Safe\Exceptions\SsdeepException
- Safe\Exceptions\Ssh2Exception
- Safe\Exceptions\StatsException
- Safe\Exceptions\StreamException
- Safe\Exceptions\StringsException
- Safe\Exceptions\SwooleException
- Safe\Exceptions\UodbcException
- Safe\Exceptions\UopzException
- Safe\Exceptions\UrlException
- Safe\Exceptions\VarException
- Safe\Exceptions\XdiffException
- Safe\Exceptions\XmlException
- Safe\Exceptions\XmlrpcException
- Safe\Exceptions\YamlException
- Safe\Exceptions\YazException
- Safe\Exceptions\ZipException
- Safe\Exceptions\ZlibException
- �
- Symfony\Contracts\Service\Attribute\SubscribedService
- Symfony\Contracts\Service\Attribute\Required
- Symfony\Contracts\Service\ResetInterface
- Symfony\Contracts\Service\ServiceLocatorTrait
- Symfony\Contracts\Service\ServiceProviderInterface
- Symfony\Contracts\Service\ServiceSubscriberInterface
- Symfony\Contracts\Service\ServiceSubscriberTrait
- Symfony\Contracts\Cache\CacheInterface
- Symfony\Contracts\Cache\CacheTrait
- Symfony\Contracts\Cache\CallbackInterface
- Symfony\Contracts\Cache\ItemInterface
- Symfony\Contracts\Cache\TagAwareCacheInterface
- Symfony\Component\VarExporter\Exception\NotInstantiableTypeException
- Symfony\Component\VarExporter\Exception\LogicException
- Symfony\Component\VarExporter\Exception\ClassNotFoundException
- Symfony\Component\VarExporter\Exception\ExceptionInterface
- Symfony\Component\VarExporter\Hydrator
- Symfony\Component\VarExporter\Instantiator
- Symfony\Component\VarExporter\Internal\LazyObjectTrait
- Symfony\Component\VarExporter\Internal\LazyObjectRegistry
- Symfony\Component\VarExporter\Internal\LazyObjectState
- Symfony\Component\VarExporter\Internal\Reference
- Symfony\Component\VarExporter\Internal\Hydrator
- Symfony\Component\VarExporter\Internal\Registry
- Symfony\Component\VarExporter\Internal\Values
- Symfony\Component\VarExporter\Internal\Exporter
- Symfony\Component\VarExporter\LazyGhostTrait
- Symfony\Component\VarExporter\LazyObjectInterface
- Symfony\Component\VarExporter\LazyProxyTrait
- Symfony\Component\VarExporter\ProxyHelper
- Symfony\Component\VarExporter\VarExporter
- Symfony\Component\Cache\Adapter\NullAdapter
- Symfony\Component\Cache\Adapter\ProxyAdapter
- Symfony\Component\Cache\Adapter\DoctrineDbalAdapter
- Symfony\Component\Cache\Adapter\AbstractAdapter
- Symfony\Component\Cache\Adapter\TagAwareAdapterInterface
- Symfony\Component\Cache\Adapter\MemcachedAdapter
- Symfony\Component\Cache\Adapter\ArrayAdapter
- Symfony\Component\Cache\Adapter\Psr16Adapter
- Symfony\Component\Cache\Adapter\AdapterInterface
- Symfony\Component\Cache\Adapter\ParameterNormalizer
- Symfony\Component\Cache\Adapter\PhpFilesAdapter
- Symfony\Component\Cache\Adapter\FilesystemAdapter
- Symfony\Component\Cache\Adapter\TagAwareAdapter
- Symfony\Component\Cache\Adapter\RedisTagAwareAdapter
- Symfony\Component\Cache\Adapter\AbstractTagAwareAdapter
- Symfony\Component\Cache\Adapter\ChainAdapter
- Symfony\Component\Cache\Adapter\FilesystemTagAwareAdapter
- Symfony\Component\Cache\Adapter\PdoAdapter
- Symfony\Component\Cache\Adapter\ApcuAdapter
- Symfony\Component\Cache\Adapter\CouchbaseBucketAdapter
- Symfony\Component\Cache\Adapter\TraceableAdapter
- Symfony\Component\Cache\Adapter\PhpArrayAdapter
- Symfony\Component\Cache\Adapter\RedisAdapter
- Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter
- Symfony\Component\Cache\Adapter\CouchbaseCollectionAdapter
- Symfony\Component\Cache\CacheItem
- Symfony\Component\Cache\Exception\LogicException
- Symfony\Component\Cache\Exception\InvalidArgumentException
- Symfony\Component\Cache\Exception\CacheException
- Symfony\Component\Cache\LockRegistry
- Symfony\Component\Cache\Marshaller\TagAwareMarshaller
- Symfony\Component\Cache\Marshaller\DefaultMarshaller
- Symfony\Component\Cache\Marshaller\SodiumMarshaller
- Symfony\Component\Cache\Marshaller\MarshallerInterface
- Symfony\Component\Cache\Marshaller\DeflateMarshaller
- Symfony\Component\Cache\Messenger\EarlyExpirationMessage
- Symfony\Component\Cache\Messenger\EarlyExpirationDispatcher
- Symfony\Component\Cache\Messenger\EarlyExpirationHandler
- Symfony\Component\Cache\PruneableInterface
- Symfony\Component\Cache\ResettableInterface
- Symfony\Component\Cache\Traits\ContractsTrait
- Symfony\Component\Cache\Traits\RedisClusterProxy
- Symfony\Component\Cache\Traits\FilesystemTrait
- Symfony\Component\Cache\Traits\Redis6Proxy

Fatal error: Declaration of Symfony\Component\Cache\Traits\Redis5Proxy::_compress($value) must be compatible with Redis::_compress(string $value): string in /shared/backups/github/class-finder-issues/vendor/symfony/cache/Traits/Redis5Proxy.php on line 64

Call Stack:
    0.0002     697600   1. {main}() /shared/backups/github/class-finder-issues/find.php:0
    0.0661    8288544   2. Kcs\ClassFinder\Iterator\ClassIterator->next() /shared/backups/github/class-finder-issues/find.php:16
    0.0661    8288544   3. Generator->next() /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/ClassIterator.php:60
    0.0661    8288544   4. Kcs\ClassFinder\Iterator\ClassIterator->next() /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/ComposerIterator.php:81
    0.0661    8288544   5. Generator->next() /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/ClassIterator.php:60
    0.0661    8288544   6. Kcs\ClassFinder\Iterator\Psr4Iterator->getGenerator() /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/ClassIterator.php:60
    0.0661    8288624   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/vendor/symfony/cache/Traits/Redis5Proxy.php') /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/Psr4Iterator.php:96
    0.0671    8630960   8. include_once('/shared/backups/github/class-finder-issues/vendor/symfony/cache/Traits/Redis5Proxy.php') /shared/backups/github/class-finder-issues/vendor/kcs/class-finder/lib/Iterator/Psr4Iterator.php:60

NOTE no workaround seems possible (even with notPath)

`ErrorHandler::handleError()` should accept `?bool` return value

PHP Manual says that the handler signature must be like this:

handler(
    int $errno,
    string $errstr,
    string $errfile = ?,
    int $errline = ?,
    array $errcontext = ?
): bool

However, there are many libraries that return void or null. My Laravel project with Larastan crashes on phpstan analyze.

In XXX.php line xxx:
                                                                                                                                         
  During inheritance of IteratorAggregate: Uncaught TypeError: Kcs\ClassFinder\Util\ErrorHandler::handleError(): Return value must be o  
  f type bool, null returned in /project/vendor/kcs/class-finder/lib/Util/ErrorHandler.php:52  

Add filter for RecursiveIterator to not require all files in the selected path, but only with specific pattern in filename

Hi there!

I'm currently working on some WordPress plugins/themes and I'm using this library to easily require and find certain classes.
I was using ComposerFinder, but since I don't always use Composer (for my themes), I switched to RecursiveFinder. When using this I noticed that it was requiring some 'non-class' files as well, causing some output.
Since WordPress has their own coding standards, this can be easily fixed by only requiring files that start with class. First I tried to fix this by using filter on the Finder, but when the filter is called, the files are already included.
So I checked where the files are included and that is in RecursiveIterator. Since there was no way to filter files here (except for creating a PR), I created my own ClassIterator (and Finder to make sure my own iterator was called) where I check if the file starts with class.
This works perfectly and I thought it would be nice to add this to the package as well.
I will try to create a PR somewhere soon, this issue is more so you can maybe think of this as well and as a reminder to myself ;-)

Error handler has changed, cannot unregister the handler

I am encountering this exception in version kcs/class-finder 0.3.2 and I don't really understand it. I am on PHP 8.1. Can you assist?

The code I am ultimately executing is this:

// $namespace = 'App\Event';
$finder = (new ComposerFinder())->inNamespace($namespace);

Error in: ROOT/vendor/kcs/class-finder/lib/Util/ErrorHandler.php, line 72

 	        $previous = set_error_handler(static fn () => false);
	        restore_error_handler();
	        if ($previous !== [self::class, 'handleError']) {
	            throw new Error('Error handler has changed, cannot unregister the handler'); // @phpstan-ignore-line
	        }
	
	        restore_error_handler();
	        self::$registered = false;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.