From: Fabien Potencier Date: Fri, 18 Nov 2011 20:54:44 +0000 (+0100) Subject: optimized variable access when using PHP 5.4 X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=1b32617b977ff7d5f15393e7627b223122238674;p=konrad%2Ftwig.git optimized variable access when using PHP 5.4 --- diff --git a/CHANGELOG b/CHANGELOG index da1e22a..6cdb593 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 1.4.0 + * optimized variable access when using PHP 5.4 * changed the precedence of the .. operator to be more consistent with languages that implements such a feature like Ruby * added an Exception to Twig_Loader_Array::isFresh() method when the template does not exist to be consistent with other loaders * added Twig_Function_Node to allow more complex functions to have their own Node class diff --git a/lib/Twig/Node/Expression/Name.php b/lib/Twig/Node/Expression/Name.php index a8d206f..4b8d541 100644 --- a/lib/Twig/Node/Expression/Name.php +++ b/lib/Twig/Node/Expression/Name.php @@ -35,18 +35,29 @@ class Twig_Node_Expression_Name extends Twig_Node_Expression } elseif ($this->isSpecial()) { $compiler->raw($this->specialVars[$name]); } else { - $compiler - ->raw('$this->getContext($context, ') - ->string($name) - ; + if (version_compare(phpversion(), '5.4.0RC1', '>=') && ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables())) { + // PHP 5.4 ternary operator performance was optimized + $compiler + ->raw('(isset($context[') + ->string($name) + ->raw(']) ? $context[') + ->string($name) + ->raw('] : null)') + ; + } else { + $compiler + ->raw('$this->getContext($context, ') + ->string($name) + ; - if ($this->getAttribute('ignore_strict_check')) { - $compiler->raw(', true'); - } + if ($this->getAttribute('ignore_strict_check')) { + $compiler->raw(', true'); + } - $compiler - ->raw(')') - ; + $compiler + ->raw(')') + ; + } } } diff --git a/lib/Twig/NodeVisitor/Optimizer.php b/lib/Twig/NodeVisitor/Optimizer.php index 8a7813a..cbc61fc 100644 --- a/lib/Twig/NodeVisitor/Optimizer.php +++ b/lib/Twig/NodeVisitor/Optimizer.php @@ -56,7 +56,7 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface $this->enterOptimizeFor($node, $env); } - if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) { + if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) { if ($this->inABody) { if (!$node instanceof Twig_Node_Expression) { if (get_class($node) !== 'Twig_Node') { diff --git a/test/Twig/Tests/Node/Expression/GetAttrTest.php b/test/Twig/Tests/Node/Expression/GetAttrTest.php index e3c2eaa..264618d 100644 --- a/test/Twig/Tests/Node/Expression/GetAttrTest.php +++ b/test/Twig/Tests/Node/Expression/GetAttrTest.php @@ -49,10 +49,10 @@ class Twig_Tests_Node_Expression_GetAttrTest extends Twig_Tests_Node_TestCase $attr = new Twig_Node_Expression_Constant('bar', 0); $args = new Twig_Node(); $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ANY_CALL, 0); - $tests[] = array($node, '$this->getAttribute($this->getContext($context, "foo"), "bar")'); + $tests[] = array($node, sprintf('$this->getAttribute(%s, "bar")', $this->getVariableGetter('foo'))); $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ARRAY_CALL, 0); - $tests[] = array($node, '$this->getAttribute($this->getContext($context, "foo"), "bar", array(), "array")'); + $tests[] = array($node, sprintf('$this->getAttribute(%s, "bar", array(), "array")', $this->getVariableGetter('foo'))); $args = new Twig_Node(array( @@ -60,7 +60,7 @@ class Twig_Tests_Node_Expression_GetAttrTest extends Twig_Tests_Node_TestCase new Twig_Node_Expression_Constant('bar', 0), )); $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::METHOD_CALL, 0); - $tests[] = array($node, '$this->getAttribute($this->getContext($context, "foo"), "bar", array($this->getContext($context, "foo"), "bar", ), "method")'); + $tests[] = array($node, sprintf('$this->getAttribute(%s, "bar", array(%s, "bar", ), "method")', $this->getVariableGetter('foo'), $this->getVariableGetter('foo'))); return $tests; } diff --git a/test/Twig/Tests/Node/Expression/NameTest.php b/test/Twig/Tests/Node/Expression/NameTest.php index f041310..e77b432 100644 --- a/test/Twig/Tests/Node/Expression/NameTest.php +++ b/test/Twig/Tests/Node/Expression/NameTest.php @@ -39,10 +39,11 @@ class Twig_Tests_Node_Expression_NameTest extends Twig_Tests_Node_TestCase $context = new Twig_Node_Expression_Name('_context', 0); $env = new Twig_Environment(null, array('strict_variables' => true)); + $env1 = new Twig_Environment(null, array('strict_variables' => false)); return array( array($node, '$this->getContext($context, "foo")', $env), - array($node, '$this->getContext($context, "foo")'), + array($node, $this->getVariableGetter('foo'), $env1), array($self, '$this'), array($context, '$context'), ); diff --git a/test/Twig/Tests/Node/ForTest.php b/test/Twig/Tests/Node/ForTest.php index 68a3daa..1a9a418 100644 --- a/test/Twig/Tests/Node/ForTest.php +++ b/test/Twig/Tests/Node/ForTest.php @@ -65,9 +65,9 @@ class Twig_Tests_Node_ForTest extends Twig_Tests_Node_TestCase $tests[] = array($node, <<getContext(\$context, "items")); +\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('items')}); foreach (\$context['_seq'] as \$context["key"] => \$context["item"]) { - echo \$this->getContext(\$context, "foo"); + echo {$this->getVariableGetter('foo')}; } \$_parent = \$context['_parent']; unset(\$context['_seq'], \$context['_iterated'], \$context['key'], \$context['item'], \$context['_parent'], \$context['loop']); @@ -86,7 +86,7 @@ EOF $tests[] = array($node, <<getContext(\$context, "values")); +\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')}); \$context['loop'] = array( 'parent' => \$context['_parent'], 'index0' => 0, @@ -101,7 +101,7 @@ if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_ \$context['loop']['last'] = 1 === \$length; } foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) { - echo \$this->getContext(\$context, "foo"); + echo {$this->getVariableGetter('foo')}; ++\$context['loop']['index0']; ++\$context['loop']['index']; \$context['loop']['first'] = false; @@ -128,7 +128,7 @@ EOF $tests[] = array($node, <<getContext(\$context, "values")); +\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')}); \$context['loop'] = array( 'parent' => \$context['_parent'], 'index0' => 0, @@ -137,7 +137,7 @@ EOF ); foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) { if (true) { - echo \$this->getContext(\$context, "foo"); + echo {$this->getVariableGetter('foo')}; ++\$context['loop']['index0']; ++\$context['loop']['index']; \$context['loop']['first'] = false; @@ -160,7 +160,7 @@ EOF $tests[] = array($node, <<getContext(\$context, "values")); +\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')}); \$context['_iterated'] = false; \$context['loop'] = array( 'parent' => \$context['_parent'], @@ -176,7 +176,7 @@ if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_ \$context['loop']['last'] = 1 === \$length; } foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) { - echo \$this->getContext(\$context, "foo"); + echo {$this->getVariableGetter('foo')}; \$context['_iterated'] = true; ++\$context['loop']['index0']; ++\$context['loop']['index']; @@ -188,7 +188,7 @@ foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) { } } if (!\$context['_iterated']) { - echo \$this->getContext(\$context, "foo"); + echo {$this->getVariableGetter('foo')}; } \$_parent = \$context['_parent']; unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']); diff --git a/test/Twig/Tests/Node/IfTest.php b/test/Twig/Tests/Node/IfTest.php index e6995c8..04b92e7 100644 --- a/test/Twig/Tests/Node/IfTest.php +++ b/test/Twig/Tests/Node/IfTest.php @@ -55,7 +55,7 @@ class Twig_Tests_Node_IfTest extends Twig_Tests_Node_TestCase $tests[] = array($node, <<getContext(\$context, "foo"); + echo {$this->getVariableGetter('foo')}; } EOF ); @@ -71,9 +71,9 @@ EOF $tests[] = array($node, <<getContext(\$context, "foo"); + echo {$this->getVariableGetter('foo')}; } elseif (false) { - echo \$this->getContext(\$context, "bar"); + echo {$this->getVariableGetter('bar')}; } EOF ); @@ -87,9 +87,9 @@ EOF $tests[] = array($node, <<getContext(\$context, "foo"); + echo {$this->getVariableGetter('foo')}; } else { - echo \$this->getContext(\$context, "bar"); + echo {$this->getVariableGetter('bar')}; } EOF ); diff --git a/test/Twig/Tests/Node/SetTest.php b/test/Twig/Tests/Node/SetTest.php index d7e0d5f..d40b90d 100644 --- a/test/Twig/Tests/Node/SetTest.php +++ b/test/Twig/Tests/Node/SetTest.php @@ -64,7 +64,7 @@ EOF $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 0), new Twig_Node_Expression_Name('bar', 0)), array(), 0); $node = new Twig_Node_Set(false, $names, $values, 0); $tests[] = array($node, <<getContext(\$context, "bar")); +list(\$context["foo"], \$context["bar"]) = array("foo", {$this->getVariableGetter('bar')}); EOF ); diff --git a/test/Twig/Tests/Node/TestCase.php b/test/Twig/Tests/Node/TestCase.php index c5b974f..ec4eee4 100644 --- a/test/Twig/Tests/Node/TestCase.php +++ b/test/Twig/Tests/Node/TestCase.php @@ -37,4 +37,13 @@ abstract class Twig_Tests_Node_TestCase extends PHPUnit_Framework_TestCase { return new Twig_Environment(); } + + protected function getVariableGetter($name) + { + if (version_compare(phpversion(), '5.4.0RC1', '>=')) { + return sprintf('(isset($context["%s"]) ? $context["%s"] : null)', $name, $name); + } + + return sprintf('$this->getContext($context, "%s")', $name); + } } diff --git a/test/Twig/Tests/NodeVisitor/OptimizerTest.php b/test/Twig/Tests/NodeVisitor/OptimizerTest.php index edf6c51..94a4cfa 100644 --- a/test/Twig/Tests/NodeVisitor/OptimizerTest.php +++ b/test/Twig/Tests/NodeVisitor/OptimizerTest.php @@ -38,6 +38,10 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase public function testRenderVariableBlockOptimizer() { + if (version_compare(phpversion(), '5.4.0RC1', '>=')) { + return; + } + $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); $env->addExtension(new Twig_Extension_Optimizer()); $stream = $env->parse($env->tokenize('{{ block(name|lower) }}', 'index'));