symplify/astral

此包已被弃用,不再维护。作者建议使用nikic/php-parser包。

AST智能日常工作工具

安装数: 2,762,319

依赖者: 6

建议者: 0

安全: 0

星标: 25

关注者: 2

分支: 1

类型:phpstan-extension

This package is auto-updated.

Last update: 2022-08-29 21:45:23 UTC


README

Downloads total

安装

composer require symplify/astral

添加到Symfony项目

config/config.php中注册包

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\Astral\ValueObject\AstralConfig::FILE_PATH;

return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator->import(AstralConfig::FILE_PATH);
};

添加到PHPStan规则

包含在你的phpstan.neon

includes:
    - vendor/symplify/astral/config/services.neon

使用

1. 解析节点值

$value = 1000;

如何获取1000值?

use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Scalar\LNumber;
use PHPStan\Analyser\Scope;
use Symplify\Astral\NodeValue\NodeValueResolver;

final class SomeRule
{
    public function __construct(
        // PHP 8.0 promoted property syntax
        private NodeValueResolver $nodeValueResolver
    ) {
    }

    public function process(Node $node, Scope $scope): void
    {
        if ($node instanceof Assign && $node->expr instanceof LNumber) {
            $resolvedValue = $this->nodeValueResolver->resolve($node->expr, $scope->getFile());
        }
    }
}

处理静态表达式如这些

$value = 'Hey';
// "Hey"

SomeClass::class;
// "SomeClass"

class SomeClass
{
    public const VALUE = 'different';
}

SomeClass::VALUE;
// "different"

__DIR__;
// realpath of the __DIR__ in its place

2. 唯一的*Builder

原生PhpParser节点类和构建器类具有相同的简短类名。

use PhpParser\Builder\Class_;
use PhpParser\Node\Stmt\Class_;

$class = new Class_('ClassName');
$class = $class->getNode();

这会令IDE困惑,并导致使用错误的类作为类型提示。为了避免这种情况,此包提供了*Builder名称

use Symplify\Astral\ValueObject\NodeBuilder\ClassBuilder;

$classBuilder = new ClassBuilder('some_class');
$class = $classBuilder->getNode();

3. 使用简单回调遍历节点

处理节点基于遍历每一个节点。您可以使用本地的NodeVisitorNodeTraverses。但这需要创建至少2个对象,将它们连接起来并调用它们。

如果我们只需要在这个方法中执行一个小范围遍历怎么办?使用服务SimpleCallableNodeTraverser来拯救

use PhpParser\Node;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\ClassMethod;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;

/** @var ClassMethod $classMethod */
$classMethod = '...';

$simpleCallableNodeTraverser = new SimpleCallableNodeTraverser();
$simpleCallableNodeTraverser->traverseNodesWithCallable($classMethod, function (Node $node) {
    if (! $node instanceof String_) {
        return null;
    }

    $node->value = 'changed name';
    return $node;
});

4. 注册配置

在您的config/config.php中注册配置

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\Astral\ValueObject\AstralConfig;

return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator->import(AstralConfig::FILE_PATH);
};

5. SimplePhpDocParser的使用

在构造函数中需要的服务Symplify\Astral\PhpDocParser\SimplePhpDocParser,在需要的地方使用它

use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use Symplify\Astral\PhpDocParser\SimplePhpDocParser;

final class SomeClass
{
    public function __construct(
        private SimplePhpDocParser $simplePhpDocParser
    ) {
    }

    public function some(): void
    {
        $docBlock = '/** @param int $name */';

        /** @var PhpDocNode $phpDocNode */
        $simplePhpDocNode = $this->simplePhpDocParser->parseDocBlock($docBlock);

        // param extras

        /** @var TypeNode $nameParamType */
        $nameParamType = $simplePhpDocNode->getParamType('name');

        /** @var ParamTagValueNode $nameParamTagValueNode */
        $nameParamTagValueNode = $simplePhpDocNode->getParam('name');
    }
}

6. 使用PhpDocNodeTraverser遍历节点

use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Symplify\Astral\PhpDocParser\PhpDocNodeTraverser;
use Symplify\Astral\PhpDocParser\PhpDocNodeVisitor\AbstractPhpDocNodeVisitor;
use Symplify\Astral\PhpDocParser\PhpDocNodeVisitor\CallablePhpDocNodeVisitor;

$phpDocNodeTraverser = new PhpDocNodeTraverser();
$phpDocNode = new PhpDocNode([new PhpDocTagNode('@var', new VarTagValueNode(new IdentifierTypeNode('string')))]);

// A. you can use callable to traverse
$callable = function (Node $node): Node {
    if (! $node instanceof VarTagValueNode) {
        return $node;
    }

    $node->type = new IdentifierTypeNode('int');
    return $node;
};

$callablePhpDocNodeVisitor = new CallablePhpDocNodeVisitor($callable, null);
$phpDocNodeTraverser->addPhpDocNodeVisitor($callablePhpDocNodeVisitor);

// B. or class that extends AbstractPhpDocNodeVisitor
final class IntegerPhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
{
    public function enterNode(Node $node): Node|int|null
    {
        if (! $node instanceof VarTagValueNode) {
            return $node;
        }

        $node->type = new IdentifierTypeNode('int');
        return $node;
    }
}

$integerPhpDocNodeVisitor = new IntegerPhpDocNodeVisitor();
$phpDocNodeTraverser->addPhpDocNodeVisitor($integerPhpDocNodeVisitor);

// then traverse the main node
$phpDocNodeTraverser->traverse($phpDocNode);

报告问题

如果您遇到错误或想要请求新功能,请访问Symplify monorepo问题跟踪器


贡献

此包的源代码包含在Symplify monorepo中。我们欢迎在symplify/symplify上为此包做出贡献。