diff --git a/src/Node/Expression/CallExpression.php b/src/Node/Expression/CallExpression.php index 866e80d53..dd115d205 100644 --- a/src/Node/Expression/CallExpression.php +++ b/src/Node/Expression/CallExpression.php @@ -290,7 +290,12 @@ abstract class CallExpression extends AbstractExpression } $checkVisibility = $callable instanceof \Closure; - $r = new \ReflectionFunction(\Closure::fromCallable($callable)); + try { + $closure = \Closure::fromCallable($callable); + } catch (\TypeError $e) { + throw new \LogicException(sprintf('Callback for %s "%s" is not callable in the current scope.', $this->getAttribute('type'), $this->getAttribute('name')), 0, $e); + } + $r = new \ReflectionFunction($closure); if (false !== strpos($r->name, '{closure}')) { return $this->reflector = [$r, $callable, 'Closure']; diff --git a/tests/Node/Expression/CallTest.php b/tests/Node/Expression/CallTest.php index 0e66f0d3f..0f21cb33e 100644 --- a/tests/Node/Expression/CallTest.php +++ b/tests/Node/Expression/CallTest.php @@ -94,6 +94,15 @@ class CallTest extends TestCase $this->getArguments($node, [[$this, 'customFunctionWithArbitraryArguments'], []]); } + public function testGetArgumentsWithInvalidCallable() + { + // see https://github.com/twigphp/Twig/issues/3708 + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Callback for function "foo" is not callable in the current scope.'); + $node = new Node_Expression_Call([], ['type' => 'function', 'name' => 'foo', 'is_variadic' => true]); + $this->getArguments($node, ['', []]); + } + public static function customStaticFunction($arg1, $arg2 = 'default', $arg3 = []) { }