Allow inherited magic method to still run with calling class

If a static method cannot be resolved to the calling class, but the calling class has, or inherits, a `__callStatic` handler, this allows the `__callStatic` handler to be used with the calling class, and not the inherited class as would occur with reflection. This allows systems such as Laravel facades to still work.

Fixes https://github.com/twigphp/Twig/issues/3716
This commit is contained in:
Ben Thomson
2022-06-27 21:02:56 +08:00
committed by Nicolas Grekas
parent c953a77b23
commit d1457a40b6
2 changed files with 30 additions and 2 deletions
+1 -2
View File
@@ -305,8 +305,7 @@ abstract class CallExpression extends AbstractExpression
$callable = [$object, $r->name];
$callableName = (\function_exists('get_debug_type') ? get_debug_type($object) : \get_class($object)).'::'.$r->name;
} elseif ($class = $r->getClosureScopeClass()) {
$callable = [$class, $r->name];
$callableName = $class.'::'.$r->name;
$callableName = (\is_array($callable) ? $callable[0] : $class->name).'::'.$r->name;
} else {
$callable = $callableName = $r->name;
}
+29
View File
@@ -42,6 +42,7 @@ class FilterTest extends NodeTestCase
$environment->addFilter(new TwigFilter('bar', 'twig_tests_filter_dummy', ['needs_environment' => true]));
$environment->addFilter(new TwigFilter('bar_closure', \Closure::fromCallable(twig_tests_filter_dummy::class), ['needs_environment' => true]));
$environment->addFilter(new TwigFilter('barbar', 'Twig\Tests\Node\Expression\twig_tests_filter_barbar', ['needs_context' => true, 'is_variadic' => true]));
$environment->addFilter(new TwigFilter('magic_static', __NAMESPACE__.'\ChildMagicCallStub::magicStaticCall'));
$extension = new class() extends AbstractExtension {
public function getFilters(): array
@@ -135,6 +136,9 @@ class FilterTest extends NodeTestCase
$node = $this->createFilter($string, 'foobar');
$tests[] = [$node, '$this->env->getFilter(\'foobar\')->getCallable()("abc")', $environment];
$node = $this->createFilter($string, 'magic_static');
$tests[] = [$node, 'Twig\Tests\Node\Expression\ChildMagicCallStub::magicStaticCall("abc")', $environment];
return $tests;
}
@@ -190,3 +194,28 @@ function twig_tests_filter_dummy()
function twig_tests_filter_barbar($context, $string, $arg1 = null, $arg2 = null, array $args = [])
{
}
class ChildMagicCallStub extends ParentMagicCallStub
{
public static function identifier()
{
return 'child';
}
}
class ParentMagicCallStub
{
public static function identifier()
{
throw new \Exception('Identifier has not been defined');
}
public static function __callStatic($method, $arguments)
{
if ('magicStaticCall' !== $method) {
throw new \BadMethodCallException('Unexpected call to __callStatic');
}
return 'inherited_static_magic_'.static::identifier().'_'.$arguments[0];
}
}