diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 0000000..7e31783 --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,97 @@ + + Jordi Boggiano + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. +EOF; + +$finder = PhpCsFixer\Finder::create() + ->files() + ->in(__DIR__.'/src') + ->in(__DIR__.'/tests') + ->name('*.php') + ->notPath('Fixtures') +; + +$config = new PhpCsFixer\Config(); +return $config + ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()) + ->setRules([ + '@PSR2' => true, + 'binary_operator_spaces' => true, + 'blank_line_before_statement' => ['statements' => ['declare', 'return']], + 'cast_spaces' => ['space' => 'single'], + 'header_comment' => ['header' => $header], + 'statement_indentation' => ['stick_comment_to_next_continuous_control_statement' => true], + 'include' => true, + + 'class_attributes_separation' => ['elements' => ['method' => 'one', 'trait_import' => 'none']], + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_blank_lines' => true, + 'no_leading_namespace_whitespace' => true, + 'no_trailing_comma_in_singleline' => true, + 'no_whitespace_in_blank_line' => true, + 'object_operator_without_whitespace' => true, + //'phpdoc_align' => true, + 'phpdoc_indent' => true, + 'no_empty_comment' => true, + 'no_empty_phpdoc' => true, + 'phpdoc_no_access' => true, + 'phpdoc_no_package' => true, + //'phpdoc_order' => true, + 'phpdoc_scalar' => true, + 'phpdoc_trim' => true, + 'phpdoc_types' => true, + 'psr_autoloading' => true, + 'blank_lines_before_namespace' => true, + 'standardize_not_equals' => true, + 'ternary_operator_spaces' => true, + 'trailing_comma_in_multiline' => ['elements' => ['arrays']], + 'unary_operator_spaces' => true, + + 'native_function_invocation' => [ + 'include' => ['@compiler_optimized'], // Targets functions with special Zend opcodes (e.g., strlen, count) + 'scope' => 'namespaced', // Only fixes functions inside a namespace + 'strict' => true, // Removes leading \ if not native + ], + + // imports + 'no_unused_imports' => true, + 'fully_qualified_strict_types' => true, + 'single_line_after_imports' => true, + //'global_namespace_import' => ['import_classes' => true], + 'no_leading_import_slash' => true, + 'single_import_per_statement' => true, + + // PHP 7.2 migration + 'array_syntax' => true, + 'list_syntax' => true, + 'regular_callable_call' => true, + 'static_lambda' => true, + 'nullable_type_declaration_for_default_null_value' => true, + 'explicit_indirect_variable' => true, + 'visibility_required' => ['elements' => ['property', 'method', 'const']], + 'non_printable_character' => true, + 'combine_nested_dirname' => true, + 'random_api_migration' => true, + 'ternary_to_null_coalescing' => true, + 'phpdoc_to_param_type' => false, + 'declare_strict_types' => true, + 'no_superfluous_phpdoc_tags' => [ + 'allow_mixed' => true, + ], + + // TODO php 7.4 migration (one day..) + // 'phpdoc_to_property_type' => true, + ]) + ->setUsingCache(true) + ->setRiskyAllowed(true) + ->setFinder($finder) +; diff --git a/src/ClassMap.php b/src/ClassMap.php index 72304da..f4391d2 100644 --- a/src/ClassMap.php +++ b/src/ClassMap.php @@ -94,7 +94,7 @@ public function getAmbiguousClasses($duplicatesFilter = '{/(test|fixture|example $ambiguousClasses = []; foreach ($this->ambiguousClasses as $class => $paths) { - $paths = array_filter($paths, function ($path) use ($duplicatesFilter): bool { + $paths = array_filter($paths, static function ($path) use ($duplicatesFilter): bool { return !Preg::isMatch($duplicatesFilter, strtr($path, '\\', '/')); }); if (\count($paths) > 0) { @@ -157,7 +157,7 @@ public function clearPsrViolationsByPath(string $pathPrefix): void $pathPrefix = rtrim(strtr($pathPrefix, '\\', '/'), '/'); foreach ($this->psrViolations as $path => $violations) { - if ($path === $pathPrefix || 0 === \strpos($path, $pathPrefix.'/')) { + if ($path === $pathPrefix || 0 === strpos($path, $pathPrefix.'/')) { unset($this->psrViolations[$path]); } } diff --git a/src/ClassMapGenerator.php b/src/ClassMapGenerator.php index fa078d2..31ef653 100644 --- a/src/ClassMapGenerator.php +++ b/src/ClassMapGenerator.php @@ -20,7 +20,6 @@ use Composer\Pcre\Preg; use Symfony\Component\Finder\Finder; -use Composer\IO\IOInterface; /** * ClassMapGenerator @@ -57,7 +56,7 @@ public function __construct(array $extensions = ['php', 'inc']) { $this->extensions = $extensions; $this->classMap = new ClassMap; - $this->streamWrappersRegex = sprintf('{^(?:%s)://}', implode('|', array_map('preg_quote', stream_get_wrappers()))); + $this->streamWrappersRegex = \sprintf('{^(?:%s)://}', implode('|', array_map('preg_quote', stream_get_wrappers()))); } /** @@ -109,21 +108,21 @@ public function getClassMap(): ClassMap */ public function scanPaths($path, ?string $excluded = null, string $autoloadType = 'classmap', ?string $namespace = null, array $excludedDirs = []): void { - if (!in_array($autoloadType, ['psr-0', 'psr-4', 'classmap'], true)) { + if (!\in_array($autoloadType, ['psr-0', 'psr-4', 'classmap'], true)) { throw new \InvalidArgumentException('$autoloadType must be one of: "psr-0", "psr-4" or "classmap"'); } if ('classmap' !== $autoloadType) { - if (!is_string($path)) { + if (!\is_string($path)) { throw new \InvalidArgumentException('$path must be a string when specifying a psr-0 or psr-4 autoload type'); } - if (!is_string($namespace)) { + if (!\is_string($namespace)) { throw new \InvalidArgumentException('$namespace must be given (even if it is an empty string if you do not want to filter) when specifying a psr-0 or psr-4 autoload type'); } $basePath = $path; } - if (is_string($path)) { + if (\is_string($path)) { if (is_file($path)) { $path = [new \SplFileInfo($path)]; } elseif (is_dir($path) || strpos($path, '*') !== false) { @@ -144,7 +143,7 @@ public function scanPaths($path, ?string $excluded = null, string $autoloadType foreach ($path as $file) { $filePath = $file->getPathname(); - if (!in_array(pathinfo($filePath, PATHINFO_EXTENSION), $this->extensions, true)) { + if (!\in_array(pathinfo($filePath, PATHINFO_EXTENSION), $this->extensions, true)) { continue; } @@ -224,7 +223,7 @@ private function filterByNamespace(array $classes, string $filePath, string $bas $validClasses = []; $rejectedClasses = []; - $realSubPath = substr($filePath, strlen($basePath) + 1); + $realSubPath = substr($filePath, \strlen($basePath) + 1); $dotPosition = strrpos($realSubPath, '.'); $realSubPath = substr($realSubPath, 0, $dotPosition === false ? PHP_INT_MAX : $dotPosition); @@ -246,7 +245,7 @@ private function filterByNamespace(array $classes, string $filePath, string $bas $subPath = str_replace('_', DIRECTORY_SEPARATOR, $class); } } elseif ('psr-4' === $namespaceType) { - $subNamespace = ('' !== $baseNamespace) ? substr($class, strlen($baseNamespace)) : $class; + $subNamespace = ('' !== $baseNamespace) ? substr($class, \strlen($baseNamespace)) : $class; $subPath = str_replace('\\', DIRECTORY_SEPARATOR, $subNamespace); } else { throw new \InvalidArgumentException('$namespaceType must be "psr-0" or "psr-4"'); @@ -281,9 +280,6 @@ private function filterByNamespace(array $classes, string $filePath, string $bas * Checks if the given path is absolute * * @see Composer\Util\Filesystem::isAbsolutePath - * - * @param string $path - * @return bool */ private static function isAbsolutePath(string $path): bool { @@ -297,7 +293,6 @@ private static function isAbsolutePath(string $path): bool * @see Composer\Util\Filesystem::normalizePath * * @param string $path Path to the file or directory - * @return string */ private static function normalizePath(string $path): string { @@ -335,7 +330,7 @@ private static function normalizePath(string $path): string } // ensure c: is normalized to C: - $prefix = Preg::replaceCallback('{(?:^|://)[a-z]:$}i', function (array $m) { return strtoupper((string) $m[0]); }, $prefix); + $prefix = Preg::replaceCallback('{(?:^|://)[a-z]:$}i', static function (array $m) { return strtoupper((string) $m[0]); }, $prefix); return $prefix.$absolute.implode('/', $parts); } diff --git a/src/PhpFileCleaner.php b/src/PhpFileCleaner.php index 967a753..731f698 100644 --- a/src/PhpFileCleaner.php +++ b/src/PhpFileCleaner.php @@ -120,7 +120,7 @@ public function clean(): string if ($this->maxMatches === 1 && isset(self::$typeConfig[$char])) { $type = self::$typeConfig[$char]; if ( - \substr($this->contents, $this->index, $type['length']) === $type['name'] + substr($this->contents, $this->index, $type['length']) === $type['name'] && Preg::isMatch($type['pattern'], $this->contents, $match, 0, $this->index - 1) ) { return $clean . $match[0]; @@ -130,7 +130,7 @@ public function clean(): string $this->index += 1; $skip = strcspn($this->contents, self::$rejectChars, $this->index); if ($skip > 0) { - $clean .= $char . \substr($this->contents, $this->index, $skip); + $clean .= $char . substr($this->contents, $this->index, $skip); $this->index += $skip; } else { $clean .= $char; @@ -212,7 +212,7 @@ private function skipHeredoc(string $delimiter): void continue 2; case $firstDelimiterChar: if ( - \substr($this->contents, $this->index, $delimiterLength) === $delimiter + substr($this->contents, $this->index, $delimiterLength) === $delimiter && $this->match($delimiterPattern) ) { $this->index += $delimiterLength; diff --git a/src/PhpFileParser.php b/src/PhpFileParser.php index 04d9828..73ed349 100644 --- a/src/PhpFileParser.php +++ b/src/PhpFileParser.php @@ -31,7 +31,7 @@ public static function findClasses(string $path): array { $extraTypes = self::getExtraTypes(); - if (!function_exists('php_strip_whitespace')) { + if (!\function_exists('php_strip_whitespace')) { throw new RuntimeException('Classmap generation relies on the php_strip_whitespace function, but it has been disabled by the disable_functions directive.'); } @@ -55,7 +55,7 @@ public static function findClasses(string $path): array $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message']; } - throw new RuntimeException(sprintf($message, $path)); + throw new RuntimeException(\sprintf($message, $path)); } // return early if there is no chance of matching anything in this file @@ -64,7 +64,7 @@ public static function findClasses(string $path): array return []; } - $p = new PhpFileCleaner($contents, count($matches[0])); + $p = new PhpFileCleaner($contents, \count($matches[0])); $contents = $p->clean(); unset($p); @@ -78,12 +78,12 @@ public static function findClasses(string $path): array $classes = []; $namespace = ''; - for ($i = 0, $len = count($matches['type']); $i < $len; ++$i) { + for ($i = 0, $len = \count($matches['type']); $i < $len; ++$i) { if (isset($matches['ns'][$i]) && $matches['ns'][$i] !== '') { $namespace = str_replace([' ', "\t", "\r", "\n"], '', (string) $matches['nsname'][$i]) . '\\'; } else { $name = $matches['name'][$i]; - assert(is_string($name)); + \assert(\is_string($name)); // skip anon classes extending/implementing if ($name === 'extends') { continue; @@ -126,7 +126,7 @@ private static function getExtraTypes(): string if (null === $extraTypes) { $extraTypes = ''; $extraTypesArray = []; - if (PHP_VERSION_ID >= 80100 || (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>='))) { + if (PHP_VERSION_ID >= 80100 || (\defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>='))) { $extraTypes .= '|enum'; $extraTypesArray = ['enum']; } diff --git a/tests/ClassMapGeneratorTest.php b/tests/ClassMapGeneratorTest.php index b50d17b..5c0f7e6 100644 --- a/tests/ClassMapGeneratorTest.php +++ b/tests/ClassMapGeneratorTest.php @@ -45,7 +45,6 @@ protected function tearDown(): void /** * @dataProvider getTestCreateMapTests - * @param string $directory * @param array $expected */ public function testCreateMap(string $directory, array $expected): void @@ -58,7 +57,7 @@ public function testCreateMap(string $directory, array $expected): void */ public function getTestCreateMapTests(): array { - $classmap = array( + $classmap = [ 'Foo\\Bar\\A' => realpath(__DIR__) . '/Fixtures/classmap/sameNsMultipleClasses.php', 'Foo\\Bar\\B' => realpath(__DIR__) . '/Fixtures/classmap/sameNsMultipleClasses.php', 'Alpha\\A' => realpath(__DIR__) . '/Fixtures/classmap/multipleNs.php', @@ -84,55 +83,55 @@ public function getTestCreateMapTests(): array 'Smarty_Internal_Compile_Block' => realpath(__DIR__) . '/Fixtures/classmap/InvalidUnicode.php', 'Smarty_Internal_Compile_Blockclose' => realpath(__DIR__) . '/Fixtures/classmap/InvalidUnicode.php', 'ShortOpenTagDocblock' => realpath(__DIR__) . '/Fixtures/classmap/ShortOpenTagDocblock.php', - ); + ]; - $data = array( - array(__DIR__ . '/Fixtures/Namespaced', array( + $data = [ + [__DIR__ . '/Fixtures/Namespaced', [ 'Namespaced\\Bar' => realpath(__DIR__) . '/Fixtures/Namespaced/Bar.inc', 'Namespaced\\Foo' => realpath(__DIR__) . '/Fixtures/Namespaced/Foo.php', 'Namespaced\\Baz' => realpath(__DIR__) . '/Fixtures/Namespaced/Baz.php', - )), - array(__DIR__ . '/Fixtures/beta/NamespaceCollision', array( + ]], + [__DIR__ . '/Fixtures/beta/NamespaceCollision', [ 'NamespaceCollision\\A\\B\\Bar' => realpath(__DIR__) . '/Fixtures/beta/NamespaceCollision/A/B/Bar.php', 'NamespaceCollision\\A\\B\\Foo' => realpath(__DIR__) . '/Fixtures/beta/NamespaceCollision/A/B/Foo.php', - )), - array(__DIR__ . '/Fixtures/Pearlike', array( + ]], + [__DIR__ . '/Fixtures/Pearlike', [ 'Pearlike_Foo' => realpath(__DIR__) . '/Fixtures/Pearlike/Foo.php', 'Pearlike_Bar' => realpath(__DIR__) . '/Fixtures/Pearlike/Bar.php', 'Pearlike_Baz' => realpath(__DIR__) . '/Fixtures/Pearlike/Baz.php', - )), - array(__DIR__ . '/Fixtures/classmap', $classmap), - array(__DIR__ . '/Fixtures/template', array()), - ); + ]], + [__DIR__ . '/Fixtures/classmap', $classmap], + [__DIR__ . '/Fixtures/template', []], + ]; - $data[] = array(__DIR__ . '/Fixtures/php5.4', array( + $data[] = [__DIR__ . '/Fixtures/php5.4', [ 'TFoo' => __DIR__ . '/Fixtures/php5.4/traits.php', 'CFoo' => __DIR__ . '/Fixtures/php5.4/traits.php', 'Foo\\TBar' => __DIR__ . '/Fixtures/php5.4/traits.php', 'Foo\\IBar' => __DIR__ . '/Fixtures/php5.4/traits.php', 'Foo\\TFooBar' => __DIR__ . '/Fixtures/php5.4/traits.php', 'Foo\\CBar' => __DIR__ . '/Fixtures/php5.4/traits.php', - )); + ]]; - $data[] = array(__DIR__ . '/Fixtures/php7.0', array( + $data[] = [__DIR__ . '/Fixtures/php7.0', [ 'Dummy\Test\AnonClassHolder' => __DIR__ . '/Fixtures/php7.0/anonclass.php', - )); + ]]; if (PHP_VERSION_ID >= 80100) { - $data[] = array(__DIR__ . '/Fixtures/php8.1', array( + $data[] = [__DIR__ . '/Fixtures/php8.1', [ 'RolesBasicEnum' => __DIR__ . '/Fixtures/php8.1/enum_basic.php', 'RolesBackedEnum' => __DIR__ . '/Fixtures/php8.1/enum_backed.php', 'RolesClassLikeEnum' => __DIR__ . '/Fixtures/php8.1/enum_class_semantics.php', 'Foo\Bar\RolesClassLikeNamespacedEnum' => __DIR__ . '/Fixtures/php8.1/enum_namespaced.php', - )); + ]]; } - if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) { - $data[] = array(__DIR__ . '/Fixtures/hhvm3.3', array( + if (\defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) { + $data[] = [__DIR__ . '/Fixtures/hhvm3.3', [ 'FooEnum' => __DIR__ . '/Fixtures/hhvm3.3/HackEnum.php', 'Foo\BarEnum' => __DIR__ . '/Fixtures/hhvm3.3/NamespacedHackEnum.php', 'GenericsClass' => __DIR__ . '/Fixtures/hhvm3.3/Generics.php', - )); + ]]; } return $data; @@ -143,16 +142,17 @@ public function testCreateMapFinderSupport(): void $finder = new Finder(); $finder->files()->in(__DIR__ . '/Fixtures/beta/NamespaceCollision'); - self::assertEqualsNormalized(array( + self::assertEqualsNormalized([ 'NamespaceCollision\\A\\B\\Bar' => realpath(__DIR__) . '/Fixtures/beta/NamespaceCollision/A/B/Bar.php', 'NamespaceCollision\\A\\B\\Foo' => realpath(__DIR__) . '/Fixtures/beta/NamespaceCollision/A/B/Foo.php', - ), ClassMapGenerator::createMap($finder)); + ], ClassMapGenerator::createMap($finder)); } /** * @see ClassMapGenerator::isStreamWrapper() */ - public function testStreamWrapperSupport(): void { + public function testStreamWrapperSupport(): void + { /** * A stream wrapper that given `test://myfile.php` will read `test://path/to/myfile.php` where `path/to` is @@ -182,8 +182,9 @@ public function testStreamWrapperSupport(): void { * * @return bool */ - public function stream_open($path, $mode, $options, &$opened_path) { - $scheme = parse_url($path, PHP_URL_SCHEME); + public function stream_open($path, $mode, $options, &$opened_path) + { + $scheme = parse_url($path, PHP_URL_SCHEME); $varname = str_replace($scheme . '://', '', $path); $this->real = 'file://' . self::$rootPath . '/' . $varname; @@ -198,28 +199,32 @@ public function stream_open($path, $mode, $options, &$opened_path) { * * @return false|string */ - public function stream_read($count) { + public function stream_read($count) + { return $this->resource === false ? false : fgets($this->resource, (int) $count); } /** * @return array|false */ - public function stream_stat() { + public function stream_stat() + { return $this->resource === false ? false : fstat($this->resource); } /** * @return bool */ - public function stream_eof() { + public function stream_eof() + { return $this->resource === false ? true : feof($this->resource); } /** * @return void */ - public function stream_close() { + public function stream_close() + { if ($this->resource !== false) { fclose($this->resource); } @@ -228,8 +233,9 @@ public function stream_close() { /** * @return array|false */ - public function url_stat(string $path, int $flags) { - $scheme = parse_url($path, PHP_URL_SCHEME); + public function url_stat(string $path, int $flags) + { + $scheme = parse_url($path, PHP_URL_SCHEME); $varname = str_replace($scheme . '://', '', $path); return stat(self::$rootPath . '/' . $varname); @@ -237,7 +243,7 @@ public function url_stat(string $path, int $flags) { }; $testProxyStreamWrapper::$rootPath = realpath(__DIR__) . '/Fixtures/classmap'; - stream_wrapper_register('test', get_class($testProxyStreamWrapper)); + stream_wrapper_register('test', \get_class($testProxyStreamWrapper)); $arrayOfSplFileInfoStreamPaths = [ new \SplFileInfo('test://BackslashLineEndingString.php'), @@ -246,9 +252,9 @@ public function url_stat(string $path, int $flags) { self::assertSame( [ - 'Foo\\SlashedA' => 'test://BackslashLineEndingString.php', - 'Foo\\SlashedB' => 'test://BackslashLineEndingString.php', - 'Smarty_Internal_Compile_Block' => 'test://InvalidUnicode.php', + 'Foo\\SlashedA' => 'test://BackslashLineEndingString.php', + 'Foo\\SlashedB' => 'test://BackslashLineEndingString.php', + 'Smarty_Internal_Compile_Block' => 'test://InvalidUnicode.php', 'Smarty_Internal_Compile_Blockclose' => 'test://InvalidUnicode.php', ], ClassMapGenerator::createMap($arrayOfSplFileInfoStreamPaths) @@ -305,7 +311,7 @@ interface B extends Iterator {} " ); - foreach (array('test', 'fixture', 'example') as $keyword) { + foreach (['test', 'fixture', 'example'] as $keyword) { if (!is_dir($tempDir . '/ambiguous/' . $keyword)) { mkdir($tempDir . '/ambiguous/' . $keyword, 0777, true); } @@ -349,7 +355,7 @@ public function testCreateMapThrowsWhenDirectoryDoesNotExist(): void public function testCreateMapDoesNotHitRegexBacktraceLimit(): void { - $expected = array( + $expected = [ 'Foo\\StripNoise' => realpath(__DIR__) . '/Fixtures/pcrebacktracelimit/StripNoise.php', 'Foo\\VeryLongHeredoc' => realpath(__DIR__) . '/Fixtures/pcrebacktracelimit/VeryLongHeredoc.php', 'Foo\\ClassAfterLongHereDoc' => realpath(__DIR__) . '/Fixtures/pcrebacktracelimit/VeryLongHeredoc.php', @@ -357,7 +363,7 @@ public function testCreateMapDoesNotHitRegexBacktraceLimit(): void 'Foo\\VeryLongPHP73Nowdoc' => realpath(__DIR__) . '/Fixtures/pcrebacktracelimit/VeryLongPHP73Nowdoc.php', 'Foo\\ClassAfterLongNowDoc' => realpath(__DIR__) . '/Fixtures/pcrebacktracelimit/VeryLongPHP73Nowdoc.php', 'Foo\\VeryLongNowdoc' => realpath(__DIR__) . '/Fixtures/pcrebacktracelimit/VeryLongNowdoc.php', - ); + ]; ini_set('pcre.backtrack_limit', '30000'); $result = ClassMapGenerator::createMap(__DIR__ . '/Fixtures/pcrebacktracelimit'); @@ -410,10 +416,10 @@ public function testGetRawPSR4Violations(): void public function testCreateMapWithDirectoryExcluded(): void { - $expected = array( + $expected = [ 'PrefixCollision_A_B_Bar' => realpath(__DIR__) . '/Fixtures/beta/PrefixCollision/A/B/Bar.php', 'PrefixCollision_A_B_Foo' => realpath(__DIR__) . '/Fixtures/beta/PrefixCollision/A/B/Foo.php', - ); + ]; $this->generator->scanPaths(realpath(__DIR__) . '/Fixtures/beta', null, 'classmap', null, ['NamespaceCollision']); $result = $this->generator->getClassMap(); @@ -423,8 +429,6 @@ public function testCreateMapWithDirectoryExcluded(): void /** * @param array $expected * @param array $actual - * @param string $message - * @return void */ protected static function assertEqualsNormalized(array $expected, array $actual, string $message = ''): void { diff --git a/tests/PhpFileParserTest.php b/tests/PhpFileParserTest.php index 7fd816c..6d9f113 100644 --- a/tests/PhpFileParserTest.php +++ b/tests/PhpFileParserTest.php @@ -18,10 +18,7 @@ namespace Composer\ClassMapGenerator; -use Composer\ClassMapGenerator\ClassMapGenerator; use PHPUnit\Framework\TestCase; -use Symfony\Component\Finder\Finder; -use Symfony\Component\Filesystem\Filesystem; class PhpFileParserTest extends TestCase {