symplify/astral
最新稳定版本:11.1.5
Composer 安装命令:
composer require symplify/astral
包简介
Toolking for smart daily work with AST
README 文档
README
Install
composer require symplify/astral
Add to Symfony Project
Register package in 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); };
Add to PHPStan Rules
Include in your phpstan.neon:
includes: - vendor/symplify/astral/config/services.neon
Usage
1. Resolve Value of Node
$value = 1000;
How can we get the 1000 value?
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()); } } }
Work for static expressions like these:
$value = 'Hey'; // "Hey" SomeClass::class; // "SomeClass" class SomeClass { public const VALUE = 'different'; } SomeClass::VALUE; // "different" __DIR__; // realpath of the __DIR__ in its place
2. Unique *Builder Classes
Native PhpParser node class and builder class share the same short class name.
use PhpParser\Builder\Class_; use PhpParser\Node\Stmt\Class_; $class = new Class_('ClassName'); $class = $class->getNode();
This confuses IDE and lead to wrong classes being used as type hints. To avoid that, this package provides *Builder names:
use Symplify\Astral\ValueObject\NodeBuilder\ClassBuilder; $classBuilder = new ClassBuilder('some_class'); $class = $classBuilder->getNode();
3. Traverse Nodes with Simple Callback
Working with nodes is based on traversing each one of them. You can use native NodeVisitor and NodeTraverses. But that requires to create at least 2 objects, to connect them and call them.
What if we need just a small traverse right in this method? Service SimpleCallableNodeTraverser to the rescue:
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. Register Config
Register config in your 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. Usage of SimplePhpDocParser
Required services Symplify\Astral\PhpDocParser\SimplePhpDocParser in constructor, where you need it, and use it:
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. Traverse Nodes with 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);
Report Issues
In case you are experiencing a bug or want to request a new feature head over to the Symplify monorepo issue tracker
Contribute
The sources of this package are contained in the Symplify monorepo. We welcome contributions for this package on symplify/symplify.
统计信息
- 总下载量: 2.85M
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 25
- 点击次数: 1
- 依赖项目数: 6
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2020-12-27