Получить заявление об использовании из класса
Не совсем уверен в лучшем названии, но я объясню, что я спрашиваю, как могу. Предположим, у меня есть следующий файл:
MyCustomClass.php
<?php
namespace MyNamespace;
use FooNamespace\FooClass;
use BarNamespace\BarClass as Bar;
use BazNamespace\BazClass as BazSpecial;
class MyCustomClass {
protected $someDependencies = [];
public function __construct(FooClass $foo, Bar $bar) {
$someDependencies[] = $foo;
$someDependencies[] = $bar;
}
}
Теперь, если бы мне пришлось использовать отражение, я мог бы получить полностью определенные имена классов из подсказок типов в конструкции.
Тем не менее, я бы получил FooNamespace\FooClass
а также BarNamespace\BarClass
, Не, FooNamespace\FooClass
а также BarNamespace\Bar
, Я также не получил бы ссылку на BazNamespace\BazClass
,
По сути, мой вопрос: как я могу получить полностью квалифицированные имена от MyCustomClass.php
пока только зная FooClass
, Bar
, а также, BazSpecial
?
Я не хочу использовать анализатор файлов, так как это снизит производительность. Я хочу быть в состоянии сделать что-то вроде:
$class = new ReflectionClass('MyCustomClass');
...
$class->getUsedClass('FooClass'); // FooNamespace\FooClass
$class->getUsedClass('Bar'); // BarNamespace\BarClass
$class->getUsedClass('BazSpecial'); // BazNamespace\BazClass
Как бы я поступил так?
4 ответа
Поскольку никто не ответил, я полагаю, что не существует простого способа добиться этого. Поэтому я создал свой собственный класс под названием ExtendedReflectionClass
который достигает того, что мне нужно.
Я создал суть файла класса и readme, который находится внизу, так что прокрутите!.
Пример использования:
require 'ExtendedReflectionClass.php';
require 'MyCustomClass.php';
$class = new ExtendedReflectionClass('MyNamespace\Test\MyCustomClass');
$class->getUseStatements();
// [
// [
// 'class' => 'FooNamespace\FooClass',
// 'as' => 'FooClass'
// ],
// [
// 'class' => 'BarNamespace\BarClass',
// 'as' => 'Bar'
// ],
// [
// 'class' => 'BazNamespace\BazClass',
// 'as' => 'BazSpecial'
// ]
// ]
$class->hasUseStatement('FooClass'); // true
$class->hasUseStatement('BarNamespace\BarClass'); // true
$class->hasUseStatement('BazSpecial'); // true
$class->hasUseStatement('SomeNamespace\SomeClass'); // false
Я использую TokenFinderTool для этого.
По сути, он использует токены для извлечения операторов использования.
Насколько я знаю, у объектов \Reflection в php такого метода, к сожалению, пока нет.
Приведенный ниже код извлекает операторы использования импорта из файла с помощью инструмента TokenFinder.
$tokens = token_get_all(file_get_contents("/path/to/MyCompany/MyClass.php"));
a(TokenFinderTool::getUseDependencies($tokens));
Будет выводить:
array (size=9)
0 => string 'Bat\CaseTool' (length=12)
1 => string 'Bat\FileSystemTool' (length=18)
2 => string 'Bat\StringTool' (length=14)
3 => string 'Bat\ValidationTool' (length=18)
4 => string 'CopyDir\AuthorCopyDirUtil' (length=25)
5 => string 'PhpBeast\AuthorTestAggregator' (length=29)
6 => string 'PhpBeast\PrettyTestInterpreter' (length=30)
7 => string 'PhpBeast\Tool\ComparisonErrorTableTool' (length=38)
8 => string 'Tiphaine\TiphaineTool' (length=21)
Примечание: если у вас есть только имя класса, вы можете использовать этот фрагмент:
$o = new \ReflectionClass($className);
$tokens = token_get_all(file_get_contents($$o->getFileName()));
$useStatements = TokenFinderTool::getUseDependencies($tokens);
Используйте BetterReflection (композитор req roave/better-reflection)
$classInfo = (new BetterReflection())
->reflector()
->reflectClass($class);
$uses = [];
foreach ($classInfo->getDeclaringNamespaceAst()->stmts as $stmt) {
foreach ($stmt->uses??[] as $use) {
$uses[] = join('\\', $use->name->parts);
}
}
print_r($uses);
Это мое решение аналогичной задачи. Решение не учитывает вариант с as, потому что он мне не нужен. Но коротко и может быть полезно.
/**
* @param class-string $className
* @return string[]
* @throws InternalServerErrorException
*/
public static function getClassUseStatements(string $className): array
{
try {
$reflectionClass = new \ReflectionClass($className);
} catch (\ReflectionException $e) {
throw new InternalServerErrorException($e->getMessage());
}
if (false === $reflectionClass->getFileName()) {
throw new InternalServerErrorException("Can not get fileName of class '$className'.");
}
$fileContent = \file_get_contents($reflectionClass->getFileName());
if (false === $fileContent) {
throw new InternalServerErrorException(
"Can not get contents from file {$reflectionClass->getFileName()}."
);
}
$tokens = \token_get_all($fileContent);
$useStatements = [];
while (null !== key($tokens)) {
$token = \current($tokens);
if (\is_array($token) && $token[0] === T_USE) {
\next($tokens);
\next($tokens);
$token = \current($tokens);
if (\is_array($token) && $token[0] === T_NAME_QUALIFIED) {
$useStatements[] = $token[1];
}
}
\next($tokens);
}
return $useStatements;
}