从类中获取use语句

9

我不是很确定最好的标题,但我会尽力解释我的问题。假设我有以下文件:

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 的引用。
基本上,我的问题是:如何在只知道 FooClass、Bar 和 BazSpecial 的情况下,从 MyCustomClass.php 中获取完全限定名称?
我不想使用文件解析器,因为这会影响性能。我希望能够做到类似以下操作:
$class = new ReflectionClass('MyCustomClass');
...
$class->getUsedClass('FooClass'); // FooNamespace\FooClass
$class->getUsedClass('Bar'); // BarNamespace\BarClass
$class->getUsedClass('BazSpecial'); // BazNamespace\BazClass

我该如何做到这一点?
4个回答

2
鉴于没有人回答,我认为没有简单的方法来实现这一点。因此,我创建了自己的类,名为ExtendedReflectionClass,它可以实现我所需的功能。
我已经创建了一个代码片段,其中包含类文件和自述文件,请向下滚动查看! ExtendedReflectionClass 用法示例:
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

  1. 我猜我没有看到创建一个包的必要性...我甚至不记得我需要它做什么了,那是4年前的事了。
  2. 是的,我知道,但我认为在概念验证中,我并没有看到使用composer的必要性,只需两个require语句即可。你所说的UAF是什么意思?
  3. 谢谢。但愿我能记得我当时需要它做什么。
- Ozzy

0

使用 BetterReflection(composer 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);

0

我用TokenFinderTool来实现这个功能。

基本上,它使用标记(token)来提取use语句。

据我所知,在php中的\Reflection对象还没有这样的方法。

下面的代码使用TokenFinder工具从文件中提取了use导入语句。

$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);

0

这是我针对类似任务的解决方案。该解决方案不考虑使用“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;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接