如何在PHP中提取属性声明的起始行?

5

使用反射可以轻松获取源文件中方法的起始和结束行,例如:ReflectionFunctionAbstract::getFileName()ReflectionFunctionAbstract::getStartLine()ReflectionFunctionAbstract::getEndLine() 提供了这种功能。然而,对于属性似乎不起作用。在类定义中提取至少属性声明的起始行和文件名的最佳方法是什么?


你有尝试过的例子吗?你尝试了什么? - JRizz
2个回答

3

这并不是微不足道的,但也不太难。

您可以通过反射获取定义属性的类。然后,您可以从那里获取文件名。然后,您只需对文件进行分词,并检查属性声明所在的行,或逐行遍历文件并进行字符串匹配即可。

以下是可能的一种方法:

$reflector      = new ReflectionProperty('Foo', 'bar');
$declaringClass = $reflector->getDeclaringClass();
$classFile      = new SplFileObject($declaringClass->getFileName());

foreach ($classFile as $line => $content) {
    if (preg_match(
        '/
            (private|protected|public|var) # match visibility or var
            \s                             # followed 1 whitespace
            \$bar                          # followed by the var name $bar
        /x',
        $content)
    ) {
        echo $line + 1;
    }
}

这里有一个演示以证明它有效

显然,以上解决方案假设属性以某种方式声明。它还假定您的每个文件都有一个类。如果您不能确定这是正确的情况,则记号化是更好的选择。但它也更加困难。


分词是个好主意,但对我来说可能会陷入死循环:我正在编写类似 ply 的解析器生成器,需要这种功能来实现分词器的功能。这是一种引导问题,所以我可能会先采用你的解决方案,等到解析器生成器正常工作之后,再实现分词器的解决方案。 :) - Michael
在这种情况下,我建议首先查看这里:https://dev59.com/YXI95IYBdhLWcg3w7CjL。您也可能对https://github.com/nikic/PHP-Parser和https://github.com/scrutinizer-ci/php-analyzer感兴趣。 - Gordon
在开始我的项目之前,我评估了几种现有的方法,但没有发现真正适合的。然而,我对ply的工作方式印象深刻,所以我尝试将其应用到php中。 - Michael

1
使用roave/better-reflection
$classInfo = (new BetterReflection())
    ->reflector()
    ->reflectClass($class);
foreach ( $classInfo->getProperties() as $reflectionProperty) {
    $declaringClass = $reflectionProperty->getDeclaringClass()->getFileName();
    $declaringSource = $reflectionProperty->getDeclaringClass()->getLocatedSource()->getSource();
    $sourceLines = explode("\n", $declaringSource);
    $propertySource = join("\n", array_slice($sourceLines, $reflectionProperty->getStartLine(), $reflectionProperty->getEndLine()-$reflectionProperty->getStartLine()));
    $properties[$reflectionProperty->getName()] = [
        'declaringClass' => $declaringClass,
        'source' => $propertySource,
        'startLine' => $reflectionProperty->getStartLine(),
        'endLine' => $reflectionProperty->getEndLine()
    ];
}
print_r($properties);


上面的代码片段也会获取属性声明,当该属性在trait或父类中声明时。显然,这可以进行优化,因为它正在循环内部拆分源代码。

谢谢,我今天刚用了它,它运行速度快,完成任务效果很好! - Tomas Votruba

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