diff --git a/src/Php/Optimizer/FuncCallOptimizer.php b/src/Php/Optimizer/FuncCallOptimizer.php index 6c5bd757..08314c4f 100644 --- a/src/Php/Optimizer/FuncCallOptimizer.php +++ b/src/Php/Optimizer/FuncCallOptimizer.php @@ -196,6 +196,9 @@ trait FuncCallOptimizer protected function parseFuncCallWithOptimizer(string $name, Node\Expr\FuncCall $expr): string|false { foreach ($expr->args as $arg) { + if ($this->isPlaceholderExpr($arg)) { + return false; + } if ($arg instanceof Node\Arg && $arg->name !== null) { return false; } @@ -209,6 +212,9 @@ trait FuncCallOptimizer // 检测参数中使用的变量是否已定义,若变量不存在则回退到动态调用路径 // 动态路径中的 parseCallArgs() 会给出明确的错误信息 foreach ($expr->args as $arg) { + if (!$arg instanceof Node\Arg) { + continue; + } if ($this->isVarExpr($arg->value) && is_string($arg->value->name) && !$this->hasVar($arg->value->name)) { return false; } diff --git a/tests/aot/symfony/array-map-first-class-builtin.phpt b/tests/aot/symfony/array-map-first-class-builtin.phpt new file mode 100644 index 00000000..15ff0af4 --- /dev/null +++ b/tests/aot/symfony/array-map-first-class-builtin.phpt @@ -0,0 +1,29 @@ +--TEST-- +Symfony pattern: array_map with first-class builtin callable +--FILE-- + +--EXPECT-- +array(4) { + [0]=> + string(1) "1" + [1]=> + string(3) "2.5" + [2]=> + string(1) "1" + [3]=> + string(4) "name" +} +array(0) { +} diff --git a/tests/aot/symfony/context-array-union.phpt b/tests/aot/symfony/context-array-union.phpt new file mode 100644 index 00000000..8298f49c --- /dev/null +++ b/tests/aot/symfony/context-array-union.phpt @@ -0,0 +1,33 @@ +--TEST-- +Symfony pattern: context array union keeps left-hand keys +--FILE-- + $message::class, + 'alias' => 'existing', + ]; + + return $context + ['alias' => $alias, 'sender' => $sender::class]; +} + +function main(): void +{ + var_dump(logContext(new stdClass(), 'async', new SymfonyLikeSender())); +} +?> +--EXPECT-- +array(3) { + ["class"]=> + string(8) "stdClass" + ["alias"]=> + string(8) "existing" + ["sender"]=> + string(17) "SymfonyLikeSender" +} diff --git a/tests/aot/symfony/dynamic-class-new-with-null-coalesce.phpt b/tests/aot/symfony/dynamic-class-new-with-null-coalesce.phpt new file mode 100644 index 00000000..a2d9991d --- /dev/null +++ b/tests/aot/symfony/dynamic-class-new-with-null-coalesce.phpt @@ -0,0 +1,28 @@ +--TEST-- +Symfony pattern: dynamic class instantiation with null coalesce default +--FILE-- +name); + var_dump(createService(SymfonyLikeNamedService::class, 'custom')->name); +} +?> +--EXPECT-- +string(8) "fallback" +string(6) "custom" diff --git a/tests/aot/symfony/nested-static-closure-normalizer.phpt b/tests/aot/symfony/nested-static-closure-normalizer.phpt new file mode 100644 index 00000000..6ba69df8 --- /dev/null +++ b/tests/aot/symfony/nested-static-closure-normalizer.phpt @@ -0,0 +1,20 @@ +--TEST-- +Symfony pattern: static closure normalizer returns another static closure +--FILE-- + static fn () => '['.$domain.'] '.$message; + + return $normalizer('upload failed'); +} + +function main(): void +{ + $message = buildTranslator('validators'); + var_dump($message()); +} +?> +--EXPECT-- +string(26) "[validators] upload failed"