Skip to content

Commit

Permalink
feat: add skipBogonFiles method to reflection finders to prevent fata…
Browse files Browse the repository at this point in the history
…l errors in well-known cases
  • Loading branch information
alekitto committed Mar 22, 2024
1 parent 36f4cab commit 19821ab
Show file tree
Hide file tree
Showing 13 changed files with 93 additions and 5 deletions.
5 changes: 5 additions & 0 deletions lib/Finder/ComposerFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Kcs\ClassFinder\Iterator\ComposerIterator;
use Kcs\ClassFinder\Iterator\FilteredComposerIterator;
use Kcs\ClassFinder\Reflection\ReflectorFactoryInterface;
use Kcs\ClassFinder\Util\BogonFilesFilter;
use Reflector;
use RuntimeException;
use Symfony\Component\ErrorHandler\DebugClassLoader;
Expand Down Expand Up @@ -93,6 +94,10 @@ public function getIterator(): Iterator
};
}

if ($this->skipBogonClasses) {
$pathFilterCallback = BogonFilesFilter::getFileFilterFn($pathFilterCallback);
}

if ($this->namespaces || $this->dirs || $this->notNamespaces) {
$iterator = new FilteredComposerIterator(
$this->loader,
Expand Down
8 changes: 7 additions & 1 deletion lib/Finder/Psr0Finder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Kcs\ClassFinder\Iterator\Psr0Iterator;
use Kcs\ClassFinder\PathNormalizer;
use Kcs\ClassFinder\Reflection\ReflectorFactoryInterface;
use Kcs\ClassFinder\Util\BogonFilesFilter;
use Reflector;

use function substr;
Expand Down Expand Up @@ -50,11 +51,16 @@ public function setReflectorFactory(ReflectorFactoryInterface|null $reflectorFac
/** @return Iterator<Reflector> */
public function getIterator(): Iterator
{
$pathFilterCallback = $this->pathFilterCallback !== null ? ($this->pathFilterCallback)(...) : null;
if ($this->skipBogonClasses) {
$pathFilterCallback = BogonFilesFilter::getFileFilterFn($pathFilterCallback);
}

return $this->applyFilters(new Psr0Iterator(
$this->namespace,
$this->path,
reflectorFactory: $this->reflectorFactory,
pathCallback: $this->pathFilterCallback !== null ? ($this->pathFilterCallback)(...) : null,
pathCallback: $pathFilterCallback,
));
}
}
8 changes: 7 additions & 1 deletion lib/Finder/Psr4Finder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Kcs\ClassFinder\Iterator\Psr4Iterator;
use Kcs\ClassFinder\PathNormalizer;
use Kcs\ClassFinder\Reflection\ReflectorFactoryInterface;
use Kcs\ClassFinder\Util\BogonFilesFilter;
use Reflector;

use function substr;
Expand Down Expand Up @@ -50,11 +51,16 @@ public function setReflectorFactory(ReflectorFactoryInterface|null $reflectorFac
/** @return Iterator<Reflector> */
public function getIterator(): Iterator
{
$pathFilterCallback = $this->pathFilterCallback !== null ? ($this->pathFilterCallback)(...) : null;
if ($this->skipBogonClasses) {
$pathFilterCallback = BogonFilesFilter::getFileFilterFn($pathFilterCallback);
}

return $this->applyFilters(new Psr4Iterator(
$this->namespace,
$this->path,
$this->reflectorFactory,
pathCallback: $this->pathFilterCallback !== null ? ($this->pathFilterCallback)(...) : null,
pathCallback: $pathFilterCallback,
));
}
}
8 changes: 7 additions & 1 deletion lib/Finder/RecursiveFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Kcs\ClassFinder\Iterator\RecursiveIterator;
use Kcs\ClassFinder\PathNormalizer;
use Kcs\ClassFinder\Util\BogonFilesFilter;
use ReflectionClass;
use Traversable;

Expand All @@ -24,9 +25,14 @@ public function __construct(string $path)
/** @return Traversable<class-string, ReflectionClass> */
public function getIterator(): Traversable
{
$pathFilterCallback = $this->pathFilterCallback !== null ? ($this->pathFilterCallback)(...) : null;
if ($this->skipBogonClasses) {
$pathFilterCallback = BogonFilesFilter::getFileFilterFn($pathFilterCallback);
}

return $this->applyFilters(new RecursiveIterator(
$this->path,
pathCallback: $this->pathFilterCallback !== null ? ($this->pathFilterCallback)(...) : null,
pathCallback: $pathFilterCallback,
));
}
}
12 changes: 12 additions & 0 deletions lib/Finder/ReflectionFilterTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ trait ReflectionFilterTrait
{
use FinderTrait;

private bool $skipBogonClasses = false;

/**
* Prevents the inclusion of files known to possibly cause bugs/fatal errors.
*/
public function skipBogonFiles(bool $skip = true): static
{
$this->skipBogonClasses = $skip;

return $this;
}

/**
* @param T $iterator
*
Expand Down
3 changes: 2 additions & 1 deletion lib/Iterator/ComposerIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Closure;
use Composer\Autoload\ClassLoader;
use Generator;
use Kcs\ClassFinder\PathNormalizer;
use Kcs\ClassFinder\Reflection\NativeReflectorFactory;
use Kcs\ClassFinder\Reflection\ReflectorFactoryInterface;
use Kcs\ClassFinder\Util\ErrorHandler;
Expand Down Expand Up @@ -43,7 +44,7 @@ private function searchInClassMap(): Generator
{
/** @var class-string $class */
foreach ($this->classLoader->getClassMap() as $class => $file) {
if ($this->pathCallback && ! ($this->pathCallback)($file)) {
if ($this->pathCallback && ! ($this->pathCallback)(PathNormalizer::resolvePath($file))) {
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Iterator/PhpDocumentorIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ protected function isInstantiable(mixed $reflector): bool
protected function getGenerator(): Generator
{
foreach ($this->scan() as $path => $info) {
if (! $this->accept($path)) {
if (! $this->accept(PathNormalizer::resolvePath($path))) {
continue;
}

Expand Down
1 change: 1 addition & 0 deletions lib/Iterator/Psr0Iterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class_exists($class, true);
assert($include instanceof Closure);

foreach ($this->search() as $path => $info) {
$path = PathNormalizer::resolvePath($path);
if (! preg_match($pattern, $path, $m) || ! $info->isReadable()) {
continue;
}
Expand Down
1 change: 1 addition & 0 deletions lib/Iterator/Psr4Iterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class_exists($class, true);
assert($include instanceof Closure);

foreach ($this->search() as $path => $info) {
$path = PathNormalizer::resolvePath($path);
if (! preg_match($pattern, $path, $m) || ! $info->isReadable()) {
continue;
}
Expand Down
1 change: 1 addition & 0 deletions lib/Iterator/RecursiveIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ protected function getGenerator(): Generator
$pattern = defined('HHVM_VERSION') ? '/\\.(php|hh)$/i' : '/\\.php$/i';

foreach ($this->search() as $path => $info) {
$path = PathNormalizer::resolvePath($path);
if (! preg_match($pattern, $path, $m) || ! $info->isReadable()) {
continue;
}
Expand Down
30 changes: 30 additions & 0 deletions lib/Util/BogonFilesFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Kcs\ClassFinder\Util;

use Closure;

use function preg_match;

final class BogonFilesFilter
{
private const BOGON_FILES_REGEX = '#' .
// https://github.com/alekitto/class-finder/issues/13#issuecomment-2010509501
'(?:symfony/(?:cache|symfony/Component/Cache)/Traits/(?:Redis(?:Cluster)?\dProxy|ValueWrapper)\.php$)' .
'#x';

public static function getFileFilterFn(Closure|null $filter = null): Closure
{
$filter ??= static fn () => true;

return static function (string $path) use ($filter): bool {
if (preg_match(self::BOGON_FILES_REGEX, $path) === 1) {
return false;
}

return $filter($path);
};
}
}
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<directory suffix=".phpt">tests/functional/error-handler/</directory>
<file>tests/functional/nested-composer-projects/test.phpt</file>
<file>tests/issue-13/test.phpt</file>
<file>tests/issue-13/test-bogon-files-filter.phpt</file>
<file>tests/issue-13/test-path-callback.phpt</file>
</testsuite>
</testsuites>
Expand Down
18 changes: 18 additions & 0 deletions tests/issue-13/test-bogon-files-filter.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
ComposerFinder - compatibility with symfony/cache: exclude path (#13)
--FILE--
<?php
require __DIR__ . '/vendor/autoload.php';

$finder = (new Kcs\ClassFinder\Finder\ComposerFinder())
->skipBogonFiles();

$count = 0;
foreach ($finder as $className => $reflector) {
++$count;
}

echo "OK"
?>
--EXPECT--
OK

0 comments on commit 19821ab

Please sign in to comment.