feature #2635 Optimize the performance of the dot operator (fabpot)

This PR was squashed before being merged into the 2.x branch (closes #2635).

Discussion
----------

Optimize the performance of the dot operator

This is an alternative to #2359 and #2361, and closes #2326.

Basically, we don't need to call `hasExtension()` at runtime for the sandbox check when calling the dot operator as we know if it's enabled at compile time (the cache hash depends on enables extensions).

My benchmarks shows a *huge* performance improvement (**around 20%**) by doing so (especially when not using the sandbox, which is almost always the case).

Commits
-------

c917d352 fixed resetting options hash when overriding all extensions
89876d23 optimized the . operator performance
This commit is contained in:
Fabien Potencier
2018-03-02 07:58:59 -08:00
4 changed files with 14 additions and 6 deletions
+1
View File
@@ -681,6 +681,7 @@ class Twig_Environment
public function setExtensions(array $extensions)
{
$this->extensionSet->setExtensions($extensions);
$this->updateOptionsHash();
}
/**
+3 -3
View File
@@ -1432,7 +1432,7 @@ function twig_array_batch($items, $size, $fill = null)
*
* @internal
*/
function twig_get_attribute(Twig_Environment $env, Twig_Source $source, $object, $item, array $arguments = array(), $type = Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
function twig_get_attribute(Twig_Environment $env, Twig_Source $source, $object, $item, array $arguments = array(), $type = Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false, $sandboxed = false)
{
// array
if (Twig_Template::METHOD_CALL !== $type) {
@@ -1514,7 +1514,7 @@ function twig_get_attribute(Twig_Environment $env, Twig_Source $source, $object,
return true;
}
if ($env->hasExtension('Twig_Extension_Sandbox')) {
if ($sandboxed) {
$env->getExtension('Twig_Extension_Sandbox')->checkPropertyAllowed($object, $item);
}
@@ -1591,7 +1591,7 @@ function twig_get_attribute(Twig_Environment $env, Twig_Source $source, $object,
return true;
}
if ($env->hasExtension('Twig_Extension_Sandbox')) {
if ($sandboxed) {
$env->getExtension('Twig_Extension_Sandbox')->checkMethodAllowed($object, $method);
}
+9 -2
View File
@@ -23,9 +23,11 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
public function compile(Twig_Compiler $compiler)
{
$env = $compiler->getEnvironment();
// optimize array calls
if (
(!$compiler->getEnvironment()->isStrictVariables() || $this->getAttribute('ignore_strict_check'))
(!$env->isStrictVariables() || $this->getAttribute('ignore_strict_check'))
&& !$this->getAttribute('is_defined_test')
&& Twig_Template::ARRAY_CALL === $this->getAttribute('type')
) {
@@ -58,7 +60,8 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
$compiler->raw(', ')->subcompile($this->getNode('attribute'));
// only generate optional arguments when needed (to make generated code more readable)
$needFourth = $this->getAttribute('ignore_strict_check');
$needFifth = $env->hasExtension('Twig_Extension_Sandbox');
$needFourth = $needFifth || $this->getAttribute('ignore_strict_check');
$needThird = $needFourth || $this->getAttribute('is_defined_test');
$needSecond = $needThird || Twig_Template::ANY_CALL !== $this->getAttribute('type');
$needFirst = $needSecond || $this->hasNode('arguments');
@@ -83,6 +86,10 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
$compiler->raw(', ')->repr($this->getAttribute('ignore_strict_check'));
}
if ($needFifth) {
$compiler->raw(', ')->repr($env->hasExtension('Twig_Extension_Sandbox'));
}
$compiler->raw(')');
}
}
+1 -1
View File
@@ -80,7 +80,7 @@ class Twig_Tests_TemplateTest extends \PHPUnit\Framework\TestCase
$template = new Twig_TemplateTest($twig);
try {
twig_get_attribute($twig, $template->getSourceContext(), $object, $item, array(), 'any');
twig_get_attribute($twig, $template->getSourceContext(), $object, $item, array(), 'any', false, false, true);
if (!$allowed) {
$this->fail();