diff --git a/CHANGELOG b/CHANGELOG index 66ed574dc..080673f47 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ # 3.30.0 (2026-XX-XX) + * Speed up adding extensions to an environment * Fix the escaping safe analysis retaining every compiled template node for the lifetime of the environment * Speed up loading a template that the environment has already loaded * Speed up rendering by compiling a cheaper generator guard into templates diff --git a/src/Environment.php b/src/Environment.php index 105689902..c0fdfc32c 100644 --- a/src/Environment.php +++ b/src/Environment.php @@ -169,7 +169,7 @@ class Environment public function enableDebug() { $this->debug = true; - $this->updateOptionsHash(); + $this->optionsHash = null; } /** @@ -180,7 +180,7 @@ class Environment public function disableDebug() { $this->debug = false; - $this->updateOptionsHash(); + $this->optionsHash = null; } /** @@ -231,7 +231,7 @@ class Environment public function enableStrictVariables() { $this->strictVariables = true; - $this->updateOptionsHash(); + $this->optionsHash = null; } /** @@ -242,7 +242,7 @@ class Environment public function disableStrictVariables() { $this->strictVariables = false; - $this->updateOptionsHash(); + $this->optionsHash = null; } /** @@ -324,7 +324,7 @@ class Environment */ public function getTemplateClass(string $name, ?int $index = null): string { - $key = ($this->hotCache[$name] ?? $this->getLoader()->getCacheKey($name)).$this->optionsHash; + $key = ($this->hotCache[$name] ?? $this->getLoader()->getCacheKey($name)).($this->optionsHash ??= $this->getOptionsHash()); return '__TwigTemplate_'.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index); } @@ -701,7 +701,7 @@ class Environment public function addExtension(ExtensionInterface $extension) { $this->extensionSet->addExtension($extension); - $this->updateOptionsHash(); + $this->optionsHash = null; } /** @@ -712,7 +712,7 @@ class Environment public function setExtensions(array $extensions) { $this->extensionSet->setExtensions($extensions); - $this->updateOptionsHash(); + $this->optionsHash = null; } /** @@ -952,9 +952,9 @@ class Environment return $this->extensionSet->getExpressionParsers(); } - private function updateOptionsHash(): void + private function getOptionsHash(): string { - $this->optionsHash = implode(':', [ + return implode(':', [ $this->extensionSet->getSignature(), \PHP_MAJOR_VERSION, \PHP_MINOR_VERSION, diff --git a/tests/EnvironmentTest.php b/tests/EnvironmentTest.php index 9c9818fbf..cd9511e86 100644 --- a/tests/EnvironmentTest.php +++ b/tests/EnvironmentTest.php @@ -655,6 +655,44 @@ EOF FilesystemHelper::removeDir($dir); } } + + public function testTemplateClassFollowsExtensionsAddedAfterItWasComputed(): void + { + $twig = new Environment(new ArrayLoader(['index' => ''])); + $cls = $twig->getTemplateClass('index'); + + $twig->addExtension(new EnvironmentTest_Extension_WithGlobals()); + $this->assertNotSame($cls, $cls = $twig->getTemplateClass('index')); + + $twig->setExtensions([new EnvironmentTest_ExtensionWithoutRuntime()]); + $this->assertNotSame($cls, $cls = $twig->getTemplateClass('index')); + + $other = new Environment(new ArrayLoader(['index' => ''])); + $other->setExtensions([new EnvironmentTest_Extension_WithGlobals(), new EnvironmentTest_ExtensionWithoutRuntime()]); + $this->assertSame($cls, $other->getTemplateClass('index')); + } + + public function testTemplateClassFollowsDebugAndStrictVariablesChanges(): void + { + $twig = new Environment(new ArrayLoader(['index' => ''])); + $cls = $twig->getTemplateClass('index'); + + $twig->enableDebug(); + $debugCls = $twig->getTemplateClass('index'); + $this->assertNotSame($cls, $debugCls); + $this->assertSame((new Environment(new ArrayLoader(['index' => '']), ['debug' => true]))->getTemplateClass('index'), $debugCls); + + $twig->disableDebug(); + $this->assertSame($cls, $twig->getTemplateClass('index')); + + $twig->enableStrictVariables(); + $strictCls = $twig->getTemplateClass('index'); + $this->assertNotSame($cls, $strictCls); + $this->assertSame((new Environment(new ArrayLoader(['index' => '']), ['strict_variables' => true]))->getTemplateClass('index'), $strictCls); + + $twig->disableStrictVariables(); + $this->assertSame($cls, $twig->getTemplateClass('index')); + } } class EnvironmentTest_Extension_WithGlobals extends AbstractExtension