我正在创建一个
Rector
(rector/rector
) 规则,该规则应根据属性的某些属性来更改属性。
PhpParser
来自 nikic/php-parser
。
我获取属性没有问题,我只需检查当前
\PhpParser\Node
是否是 \PhpParser\Node\Stmt\Property
的实例(并且我确实得到了匹配项)。
但是,为了让我的用例匹配某些更改源数据,我还需要属性所属类的类名称 - 我尝试了以下简单的实现:
private function getClassNameFromPropertyNode(Property $propertyNode): ?string {
$currentNode = $propertyNode;
while ($currentNode !== null) {
if ($currentNode instanceof \PhpParser\Node\Stmt\Class_) {
$name = $currentNode->name;
return $name instanceof \PhpParser\Node\Identifier ? $name->toString() : null;
}
$currentNode = $currentNode->getAttribute('parent');
}
return null;
}
但它总是让我
null
...似乎$currentNode->getAttribute('parent')
这总是返回null。
如何获取当前节点的父节点和/或当前属性的类名?谢谢。
我想我已经解决了。我回到https://github.com/nikic/PHP-Parser/issues/238,它给了我一个想法 - 父属性可能没有被校长设置,我是对的。
实际上有两个问题:
parent
属性getNodeTypes()
校长的规矩连课都没上过首先,我还需要遍历
Class_
节点:
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Class_;
...
public function getNodeTypes(): array
{
return [
Property::class,
Class_::class,
];
}
然后在每个
refactor()
调用中将 parent
属性设置为当前类 FQN(完全限定名称 = 带命名空间的名称) - 为此,我首先简化了获取类名称的方法:
private function getPropertyClassFqn(Property $propertyNode): ?string {
$class = $propertyNode->getAttribute('parent');
return ($class instanceof Class_) ? $class->namespacedName->toString() : null;
}
然后在每个
refactor()
开始时我设置父级。
use PhpParser\Node;
...
public function refactor(Node $node): ?Node
{
if ($node instanceof Class_)
{
foreach ($node->stmts ?? [] as $childNode)
{
if ($childNode instanceof Property)
{
$childNode->setAttribute('parent', $node);
}
}
return $node;
}