From 279993b24d071b951c7f1f36270c6b6ceb336caf Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 2 Mar 2018 10:18:24 -0800 Subject: [PATCH 1/3] optimized performance when accessing extensions in templates --- lib/Twig/Node/CheckSecurity.php | 2 +- lib/Twig/Node/Sandbox.php | 2 +- lib/Twig/Node/SandboxedPrint.php | 2 +- lib/Twig/Profiler/Node/EnterProfile.php | 4 ++-- lib/Twig/Template.php | 10 ++++++++++ test/Twig/Tests/Node/SandboxTest.php | 2 +- test/Twig/Tests/Node/SandboxedPrintTest.php | 2 +- 7 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/Twig/Node/CheckSecurity.php b/lib/Twig/Node/CheckSecurity.php index e046723c4..d73185de8 100644 --- a/lib/Twig/Node/CheckSecurity.php +++ b/lib/Twig/Node/CheckSecurity.php @@ -46,7 +46,7 @@ class Twig_Node_CheckSecurity extends Twig_Node ->write('$functions = ')->repr(array_filter($functions))->raw(";\n\n") ->write("try {\n") ->indent() - ->write("\$this->env->getExtension('Twig_Extension_Sandbox')->checkSecurity(\n") + ->write("\$this->extensions['Twig_Extension_Sandbox']->checkSecurity(\n") ->indent() ->write(!$tags ? "array(),\n" : "array('".implode("', '", array_keys($tags))."'),\n") ->write(!$filters ? "array(),\n" : "array('".implode("', '", array_keys($filters))."'),\n") diff --git a/lib/Twig/Node/Sandbox.php b/lib/Twig/Node/Sandbox.php index 130e6086b..03a6b45bb 100644 --- a/lib/Twig/Node/Sandbox.php +++ b/lib/Twig/Node/Sandbox.php @@ -25,7 +25,7 @@ class Twig_Node_Sandbox extends Twig_Node { $compiler ->addDebugInfo($this) - ->write("\$sandbox = \$this->env->getExtension('Twig_Extension_Sandbox');\n") + ->write("\$sandbox = \$this->extensions['Twig_Extension_Sandbox'];\n") ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n") ->indent() ->write("\$sandbox->enableSandbox();\n") diff --git a/lib/Twig/Node/SandboxedPrint.php b/lib/Twig/Node/SandboxedPrint.php index 6738ddc60..eb45cb8b9 100644 --- a/lib/Twig/Node/SandboxedPrint.php +++ b/lib/Twig/Node/SandboxedPrint.php @@ -25,7 +25,7 @@ class Twig_Node_SandboxedPrint extends Twig_Node_Print { $compiler ->addDebugInfo($this) - ->write('echo $this->env->getExtension(\'Twig_Extension_Sandbox\')->ensureToStringAllowed(') + ->write('echo $this->extensions[\'Twig_Extension_Sandbox\']->ensureToStringAllowed(') ->subcompile($this->getNode('expr')) ->raw(");\n") ; diff --git a/lib/Twig/Profiler/Node/EnterProfile.php b/lib/Twig/Profiler/Node/EnterProfile.php index 69c8f7970..5a21dde28 100644 --- a/lib/Twig/Profiler/Node/EnterProfile.php +++ b/lib/Twig/Profiler/Node/EnterProfile.php @@ -24,9 +24,9 @@ class Twig_Profiler_Node_EnterProfile extends Twig_Node public function compile(Twig_Compiler $compiler) { $compiler - ->write(sprintf('$%s = $this->env->getExtension(', $this->getAttribute('var_name'))) + ->write(sprintf('$%s = $this->extensions[', $this->getAttribute('var_name'))) ->repr($this->getAttribute('extension_name')) - ->raw(");\n") + ->raw("];\n") ->write(sprintf('$%s->enter($%s = new Twig_Profiler_Profile($this->getTemplateName(), ', $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof')) ->repr($this->getAttribute('type')) ->raw(', ') diff --git a/lib/Twig/Template.php b/lib/Twig/Template.php index 030aec208..80a04e44a 100644 --- a/lib/Twig/Template.php +++ b/lib/Twig/Template.php @@ -38,9 +38,19 @@ abstract class Twig_Template protected $blocks = array(); protected $traits = array(); + /** + * @internal + */ + protected $extensions = array(); + public function __construct(Twig_Environment $env) { $this->env = $env; + foreach ($env->getExtensions() as $extension) { + // For BC/FC with namespaced aliases + $class = (new ReflectionClass(get_class($extension)))->name; + $this->extensions[ltrim($class, '\\')] = $extension; + } } /** diff --git a/test/Twig/Tests/Node/SandboxTest.php b/test/Twig/Tests/Node/SandboxTest.php index 56f487730..3c62f7bd2 100644 --- a/test/Twig/Tests/Node/SandboxTest.php +++ b/test/Twig/Tests/Node/SandboxTest.php @@ -28,7 +28,7 @@ class Twig_Tests_Node_SandboxTest extends Twig_Test_NodeTestCase $tests[] = array($node, <<env->getExtension('Twig_Extension_Sandbox'); +\$sandbox = \$this->extensions['Twig_Extension_Sandbox']; if (!\$alreadySandboxed = \$sandbox->isSandboxed()) { \$sandbox->enableSandbox(); } diff --git a/test/Twig/Tests/Node/SandboxedPrintTest.php b/test/Twig/Tests/Node/SandboxedPrintTest.php index 8bc8a755c..f263859af 100644 --- a/test/Twig/Tests/Node/SandboxedPrintTest.php +++ b/test/Twig/Tests/Node/SandboxedPrintTest.php @@ -24,7 +24,7 @@ class Twig_Tests_Node_SandboxedPrintTest extends Twig_Test_NodeTestCase $tests[] = array(new Twig_Node_SandboxedPrint(new Twig_Node_Expression_Constant('foo', 1), 1), <<env->getExtension('Twig_Extension_Sandbox')->ensureToStringAllowed("foo"); +echo \$this->extensions['Twig_Extension_Sandbox']->ensureToStringAllowed("foo"); EOF ); From f4c5152f454d86438cb53af7fbcb15061df165b9 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 2 Mar 2018 10:56:39 -0800 Subject: [PATCH 2/3] optimized calls to custom extension runtimes --- lib/Twig/Node/Expression/Call.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Twig/Node/Expression/Call.php b/lib/Twig/Node/Expression/Call.php index 727646fe6..3ba45e377 100644 --- a/lib/Twig/Node/Expression/Call.php +++ b/lib/Twig/Node/Expression/Call.php @@ -28,7 +28,13 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression $compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1])); } } elseif ($r instanceof ReflectionMethod && $callable[0] instanceof Twig_ExtensionInterface) { - $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', get_class($callable[0]), $callable[1])); + // For BC/FC with namespaced aliases + $class = (new ReflectionClass(get_class($callable[0])))->name; + if (!$compiler->getEnvironment()->hasExtension($class)) { + throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $class)); + } + + $compiler->raw(sprintf('$this->extensions[\'%s\']->%s', ltrim($class, '\\'), $callable[1])); } else { $closingParenthesis = true; $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', ucfirst($this->getAttribute('type')), $this->getAttribute('name'))); From 540c900649c8d3aade08b52ef075c6d9d74a2ba7 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 2 Mar 2018 11:43:17 -0800 Subject: [PATCH 3/3] updated CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index dc7e4273c..ab58ae8b2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 2.4.5 (2017-XX-XX) + * optimized the performance of calling an extension method at runtime * optimized the performance of the dot operator for array and method calls * added an exception when using "===" instead of "same as" * fixed possible array to string conversion concealing actual error