Skip to content

Non-scalar attribute arguments (enum cases, objects, PHP 8.5 closures) crash proxy generation #601

Description

@lisachenko

Summary

AttributeGroupsGenerator copies attributes to the proxy by feeding runtime ReflectionAttribute::getArguments() values into php-parser's BuilderFactory::args()BuilderHelpers::normalizeValue(), which only accepts scalars/arrays. Any attribute argument that evaluates to an object kills the whole weave with LogicException: Invalid value.

Affected argument kinds:

  • enum cases (PHP 8.1): #[RichAttr(Status::Active)]
  • new in initializers (PHP 8.1): #[RichAttr(new \ArrayObject([1, 2]))]
  • closures / first-class callables in constant expressions (PHP 8.5): #[ExprAttr(strlen(...))], #[ExprAttr(static function (int $x): int { return $x * 2; })]

Found during the PHP 8.5 support audit (PR #597). Reproduces on PHP 8.4 / 8.5.10 / 8.6.0beta2 (closure cases are 8.5+ syntax).

Reproduction

TRANSFORM ERROR for Php81NonScalarAttributeArgs: Invalid value

LogicException: Invalid value in vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php:276
#0 PhpParser\BuilderFactory->args()
#1 src/Proxy/Generator/AttributeGroupsGenerator.php(59)
#2 src/Proxy/ClassProxyGenerator.php(153)
#3 src/Instrument/Transformer/WeavingTransformer.php(167)

Fixtures: tests/Fixtures/audit/src/Php81NonScalarAttributeArgs.php, tests/Fixtures/audit/src/Php85ClosuresInConstExpr.php (audit branch).

Even where it does not crash, round-tripping runtime values constant-folds the original expression (e.g. a const fetch Foo::BAR is baked into its value), losing source fidelity in the proxy.

Root cause

src/Proxy/Generator/AttributeGroupsGenerator.php:43-65 uses evaluated argument values instead of the attribute's AST.

Proposed fix

When the reflector is goaop/parser-reflection (weave-time path), take the raw AttributeGroup AST nodes (via getNode()/getTypeNode()-style access, same duck-typing the generators already use for types and defaults in ParameterGenerator/MethodGenerator) and clone them into the proxy verbatim — names already resolved to FQCN or re-resolved against the original namespace. Fall back to the current value-based path only for native reflection, and there skip (with a clear exception message) argument values that cannot be represented.

This is the same AST-first strategy already applied for PHP 8.5 closure/FCC parameter defaults (ValueGenerator::fromExprNode()), extended to attributes.

Environment

  • goaop/framework master (4.0-dev), nikic/php-parser 5.8.0, PHP 8.4 / 8.5.10 / 8.6.0beta2

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions