function PhpFileParser::findClasses
Extract the classes in the given file
Parameters
string $path The file to check:
Return value
list<class-string> The found classes
Throws
\RuntimeException
1 call to PhpFileParser::findClasses()
- ClassMapGenerator::scanPaths in vendor/
composer/ class-map-generator/ src/ ClassMapGenerator.php - Iterate over all files in the given directory searching for classes
File
-
vendor/
composer/ class-map-generator/ src/ PhpFileParser.php, line 29
Class
- PhpFileParser
- @author Jordi Boggiano <j.boggiano@seld.be>
Namespace
Composer\ClassMapGeneratorCode
public static function findClasses(string $path) : array {
$extraTypes = self::getExtraTypes();
// Use @ here instead of Silencer to actively suppress 'unhelpful' output
// @link https://github.com/composer/composer/pull/4886
$contents = @php_strip_whitespace($path);
if ('' === $contents) {
if (!file_exists($path)) {
$message = 'File at "%s" does not exist, check your classmap definitions';
}
elseif (!self::isReadable($path)) {
$message = 'File at "%s" is not readable, check its permissions';
}
elseif ('' === trim((string) file_get_contents($path))) {
// The input file was really empty and thus contains no classes
return array();
}
else {
$message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted';
}
$error = error_get_last();
if (isset($error['message'])) {
$message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];
}
throw new \RuntimeException(sprintf($message, $path));
}
// return early if there is no chance of matching anything in this file
Preg::matchAllStrictGroups('{\\b(?:class|interface|trait' . $extraTypes . ')\\s}i', $contents, $matches);
if (0 === \count($matches)) {
return array();
}
$p = new PhpFileCleaner($contents, count($matches[0]));
$contents = $p->clean();
unset($p);
Preg::matchAll('{
(?:
\\b(?<![\\\\$:>])(?P<type>class|interface|trait' . $extraTypes . ') \\s++ (?P<name>[a-zA-Z_\\x7f-\\xff:][a-zA-Z0-9_\\x7f-\\xff:\\-]*+)
| \\b(?<![\\\\$:>])(?P<ns>namespace) (?P<nsname>\\s++[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*+(?:\\s*+\\\\\\s*+[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*+)*+)? \\s*+ [\\{;]
)
}ix', $contents, $matches);
$classes = array();
$namespace = '';
for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
if (isset($matches['ns'][$i]) && $matches['ns'][$i] !== '') {
$namespace = str_replace(array(
' ',
"\t",
"\r",
"\n",
), '', (string) $matches['nsname'][$i]) . '\\';
}
else {
$name = $matches['name'][$i];
assert(is_string($name));
// skip anon classes extending/implementing
if ($name === 'extends' || $name === 'implements') {
continue;
}
if ($name[0] === ':') {
// This is an XHP class, https://github.com/facebook/xhp
$name = 'xhp' . substr(str_replace(array(
'-',
':',
), array(
'_',
'__',
), $name), 1);
}
elseif (strtolower((string) $matches['type'][$i]) === 'enum') {
// something like:
// enum Foo: int { HERP = '123'; }
// The regex above captures the colon, which isn't part of
// the class name.
// or:
// enum Foo:int { HERP = '123'; }
// The regex above captures the colon and type, which isn't part of
// the class name.
$colonPos = strrpos($name, ':');
if (false !== $colonPos) {
$name = substr($name, 0, $colonPos);
}
}
/** @var class-string */
$className = ltrim($namespace . $name, '\\');
$classes[] = $className;
}
}
return $classes;
}