定制 respect/fluent-analysis 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

respect/fluent-analysis

最新稳定版本:2.0.1

Composer 安装命令:

composer require respect/fluent-analysis

包简介

PHPStan extension for Respect/Fluent builder method resolution

README 文档

README

PHPStan extension for Respect/Fluent builders. Provides method resolution, parameter validation, tuple-typed getNodes(), and type narrowing through assertion methods.

Fluent builders use __call to resolve method names to class instances. Since those methods don't exist as real declarations, PHPStan reports errors and can't validate arguments. This extension teaches PHPStan what each method does: its parameters, return type, and the exact tuple of accumulated nodes.

$stack = Middleware::cors('*')->rateLimit(100);

// PHPStan knows:
//   cors()      accepts (string $origin = '*')
//   rateLimit() accepts (int $maxRequests = 60)
//   getNodes()  returns array{Cors, RateLimit}
//   $stack      is Middleware<array{Cors, RateLimit}>

$stack->getNodes()[0]; // PHPStan infers: Cors
$stack->typo();        // PHPStan error: method not found
$stack->cors(42);      // PHPStan error: int given, string expected

Installation

composer require --dev respect/fluent-analysis

Requires PHP 8.5+ and PHPStan 2.1+.

Setup

Libraries that ship a Fluent builder declare it in their fluent.neon:

parameters:
    fluent:
        builders:
            - builder: App\MiddlewareStack

The extension loads automatically via phpstan/extension-installer. Method maps are built from #[FluentNamespace] attributes at PHPStan boot.

Adding custom namespaces

To add extra node namespaces to an existing builder (e.g. custom validators):

parameters:
    fluent:
        builders:
            - builder: Respect\Validation\ValidatorBuilder
              namespace: App\Validators

Entries from multiple neon files are merged automatically. Each package, extension, or user project can append entries independently.

Generating config for new projects

For projects that define their own #[FluentNamespace] builders:

vendor/bin/fluent-analysis generate

This scans your composer.json autoload entries for builder classes and writes a fluent.neon with the builder list and service registrations.

Features

Method resolution

Every method on your builder is resolved to its target class. PHPStan reports unknown methods as errors: typos are caught at analysis time.

Constructor parameter forwarding

Method parameters come from the target class constructor. If Cors has __construct(string $origin = '*'), then ->cors() accepts the same signature. Type mismatches are reported.

Tuple-typed getNodes()

The extension tracks which node types are accumulated through the chain. getNodes() returns a precise tuple instead of array<int, object>:

$builder = new MiddlewareStack();
$chain = $builder->cors('*')->rateLimit(100)->auth('bearer');

// PHPStan knows: array{Cors, RateLimit, Auth}
$nodes = $chain->getNodes();

// Individual elements are typed
$nodes[0]; // Cors
$nodes[1]; // RateLimit
$nodes[2]; // Auth

Tuple tracking works through variable assignments and static calls:

$a = MiddlewareStack::cors('*');
$b = $a->rateLimit(100);
$b->getNodes(); // array{Cors, RateLimit}

Deprecation forwarding

If a target class is marked @deprecated, the fluent method inherits the deprecation. PHPStan reports it wherever the method is called.

Composable prefix support

For builders using Respect/Fluent's composable prefixes (like Validation's notEmail(), nullOrStringType()), the extension resolves composed methods with correct parameter signatures.

Type narrowing

Builders can narrow the type of a variable through assertion methods. Node classes declare their assurance via the #[Assurance] attribute, assertion methods are marked with #[AssuranceAssertion], and #[AssuranceParameter] identifies the validated parameter and constructor parameters used for type resolution.

Void assertion methods narrow unconditionally:

$builder->intNode()->doAssert($x);
// PHPStan now knows $x is int

Bool assertion methods work as type guards:

if ($builder->intNode()->isOk($x)) {
    // $x is int here
}
// $x is not int here

Chained nodes intersect their assurances:

$builder->intNode()->numericNode()->doAssert($x);
// int ∩ (int|float|numeric-string) = int

The extension supports several assurance modes through the #[Assurance] attribute:

  • type — a fixed type string (e.g. int, float|int|numeric-string)
  • #[AssuranceParameter] — the type is taken from a constructor parameter annotated with the attribute (e.g. a class-string parameter)
  • from: value — narrows to the argument's literal type
  • from: member — narrows to the iterable value type of the argument
  • from: elements — narrows to an array of the inner assurance type
  • compose: union|intersect — combines assurances from multiple builder arguments

How it works

The extension registers three PHPStan hooks:

  1. FluentMethodsExtension (MethodsClassReflectionExtension) — tells PHPStan which methods exist on each builder, with parameters extracted from the target class constructor.

  2. FluentDynamicReturnTypeExtension (DynamicMethodReturnTypeExtension + DynamicStaticMethodReturnTypeExtension) — intercepts each method call to track accumulated node types as a GenericObjectType wrapping a ConstantArrayType tuple. When getNodes() is called, the tuple is returned directly. Also accumulates assurance types through the chain.

  3. FluentTypeSpecifyingExtension (MethodTypeSpecifyingExtension) — enables type narrowing in control flow. When a builder's assertion method is called, accumulated assurances are applied to narrow the input variable's type. Supports void assertions (unconditional) and bool guards (conditional).

The extensions share a MethodMap for method resolution and an AssuranceMap for type narrowing configuration, both with parent-class fallback for builder inheritance.

At PHPStan boot, MethodMapFactory reads the builders parameter, reflects each builder's #[FluentNamespace] attribute, discovers classes in the declared namespaces, and builds the method/assurance maps. Extra namespaces from user config are merged via withNamespace().

FluentAnalysis vs FluentGen

Another similar project is FluentGen.

Both are complementary, offering IDE support and type inference as separate packages.

FluentAnalysis FluentGen
Generated files None Interface files per builder + prefix
Return type Builder<array{A, B, C}> Builder (via @mixin)
getNodes() type array{A, B, C} (exact tuple) array<int, Node> (generic)
Element access $nodes[0] typed as A mixed
Deprecation Forwarded automatically Must regenerate
Composable prefixes Resolved from attribute Full method signatures
Type narrowing Assertion methods narrow input types Not supported
IDE support PHPStan-powered (PhpStorm, VS Code) Direct IDE autocomplete

统计信息

  • 总下载量: 86
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 2
  • 点击次数: 5
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 2
  • Watchers: 1
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: ISC
  • 更新时间: 2026-03-25

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固