-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Fix support for named closures #3702
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -149,8 +149,6 @@ public function addExtension(ExtensionInterface $extension) | |||
throw new \LogicException(sprintf('Unable to register extension "%s" as it is already registered.', $class)); | |||
} | |||
|
|||
// For BC/FC with namespaced aliases | |||
$class = (new \ReflectionClass($class))->name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed because $class = \get_class($extension)
, which means aliases are already resolved
$closingParenthesis = true; | ||
$isArray = true; | ||
$compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), ', ucfirst($this->getAttribute('type')), $this->getAttribute('name'))); | ||
$compiler->raw(sprintf('$this->env->get%s(\'%s\')->getCallable()', ucfirst($this->getAttribute('type')), $this->getAttribute('name'))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHP 7.1 means we can remove using call_user_func_array()
and use an inline call instead.
@@ -245,10 +236,7 @@ protected function normalizeName($name) | |||
|
|||
private function getCallableParameters($callable, bool $isVariadic): array | |||
{ | |||
list($r) = $this->reflectCallable($callable); | |||
if (null === $r) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a reflection object is now always returned, even for magic methods
26ae5a0
to
e0db9aa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to add tests in FunctionTest showing that using Closure::fromCallable on an extension method actually compiles to the optimized $this->extensions['extension_class_name']->method()
call rather than to $this->env->getFunction('foo')->getCallable()
which triggers a full initialization of extensions.
8ec8522
to
5a13c52
Compare
Test added. |
The tests you added don't cover the case of calling extension methods |
5a13c52
to
163f074
Compare
Test added :) |
Thank you @nicolas-grekas. |
@nicolas-grekas this PR has caused an issue with callables that point to Laravel facades in Winter CMS: wintercms/winter#557 (comment). Do you have any idea what would be causing that and how we can go about fixing it? |
It looks the code should be changed like this: --- a/src/Node/Expression/CallExpression.php
+++ b/src/Node/Expression/CallExpression.php
@@ -305,8 +305,8 @@ 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;
+ $callable = [$class->name, $r->name];
+ $callableName = $class->name.'::'.$r->name;
} else { Would you be available to send this with a test case, please? |
Off the top of my head, it would probably look something like this: class CallStaticCallable
{
public static function __callStatic($name, $arguments)
{
if ($name === 'magicMethod') {
return 'mischief managed';
}
}
}
$callable = [CallStaticCallable::class, 'magicMethod']; Is that enough for you to go off of @nicolas-grekas? |
That should definitely help. Would you be up to submit a PR with everything wrapped up? |
At the moment I don't have the time unfortunately, however perhaps @mjauvin, @damsfx, @WebVPF, or @arvislacis would be willing to as the issue is directly impacting them. |
@nicolas-grekas here's a patch that has the full test case: diff --git a/tests/Node/Expression/FilterTest.php b/tests/Node/Expression/FilterTest.php
index ef7c82cb..1a86e800 100644
--- a/tests/Node/Expression/FilterTest.php
+++ b/tests/Node/Expression/FilterTest.php
@@ -49,6 +49,7 @@ class FilterTest extends NodeTestCase
return [
new TwigFilter('foo', \Closure::fromCallable([$this, 'foo'])),
new TwigFilter('foobar', \Closure::fromCallable([$this, 'foobar'])),
+ new TwigFilter('alias_bar', ['Twig_Test_Alias_Class', 'test']),
];
}
@@ -135,6 +136,10 @@ class FilterTest extends NodeTestCase
$node = $this->createFilter($string, 'foobar');
$tests[] = [$node, '$this->env->getFilter(\'foobar\')->getCallable()("abc")', $environment];
+ // aliased class
+ $node = $this->createFilter($string, 'alias_bar');
+ $tests[] = [$node, '$this->env->getFilter(\'alias_bar\')->getCallable()("abc")', $environment];
+
return $tests;
}
@@ -190,3 +195,31 @@ function twig_tests_filter_dummy()
function twig_tests_filter_barbar($context, $string, $arg1 = null, $arg2 = null, array $args = [])
{
}
+
+// Sample class with a magic method
+class Twig_Test_Parent_Class
+{
+ public static function getAccessor()
+ {
+ throw new \Exception('Accessor not set');
+ }
+
+ public static function __callStatic($name, $arguments)
+ {
+ $accessor = static::getAccessor();
+
+ if ($name === 'test') {
+ return 'received ' . $arguments[0];
+ }
+ }
+}
+
+class Twig_Test_Child_Class extends Twig_Test_Parent_Class
+{
+ public static function getAccessor()
+ {
+ return 'child';
+ }
+}
+
+class_alias(Twig_Test_Child_Class::class, 'Twig_Test_Alias_Class'); It passes in the test case, in the sense that it creates the compiled What seems to happen is that the I hope that makes sense - let me know if you need any further info. |
Could you open an issue with the details instead of commenting on a merged PR ? It would avoid loosing track of the issue. |
As spotted by @stof on symfony/symfony#46335 (comment)