This PR was merged into the 3.x branch.
Discussion
----------
Speed up traversing nodes with node visitors
`NodeTraverser` walks the whole tree once per node visitor, and it iterated over the children of each node with `foreach ($node as ...)`, which allocates an `ArrayIterator` per node and per visitor. It now reads the children array through a new internal `Node::getNodes()` method. On the Symfony Demo, where six visitors are registered, walking the 21k nodes of its 52 templates takes half the instructions it took, and warming up its Twig cache runs 15% fewer instructions and takes 520ms instead of 566ms.
The traverser doesn't go through `getIterator()` anymore, so a subclass overriding it to hide children from visitors would be bypassed, and one declaring its own `getNodes()` would clash; I found none in Twig, Symfony or UX. Calling `getArrayCopy()` on the iterator returned by `getIterator()` would avoid the new method, but it saves 13% of the traversal instructions instead of 50%: `new \ArrayIterator()` and `getArrayCopy()` both copy the array.
<details>
<summary>Merge-up notes</summary>
To 4.x: the patch applies as is (I ran the 4.x suite with it), the CHANGELOG entry doesn't go to 4.x.
</details>
Commits
-------
69fefec125 Speed up traversing nodes with node visitors
This PR was merged into the 3.x branch.
Discussion
----------
Allow skipping the directory check when adding paths to `FilesystemLoader`
`FilesystemLoader::addPath()` and `prependPath()` call `is_dir()` on each path, so an app built from a compiled container pays for it on each request, even though the paths were checked when the container was built. This adds a third argument to skip the check:
```php
$loader->addPath($templateDir, 'admin', false);
```
It's read with `func_get_arg()` because Drupal and Contao override both methods with two arguments. On the Symfony Demo, where TwigBundle registers 14 paths, building the loader goes from 64µs to 21µs per request once TwigBundle passes `false` (symfony/symfony#66334).
<details>
<summary>Merge-up notes</summary>
To 4.x: declare the argument for real, `bool $check = true`, instead of reading it with `func_get_arg()`; the tests apply as is. The CHANGELOG and `doc/deprecated.rst` entries don't go to 4.x, and the `versionadded` block has to be removed from `doc/api.rst` since the 4.x docs have none.
</details>
Commits
-------
9e1e2e2cea Allow skipping the directory check when adding paths to `FilesystemLoader`
This PR was merged into the 3.x branch.
Discussion
----------
Fix the deprecated tag generating invalid PHP for an integer message
Closes#4978
Commits
-------
c6f1ef9521 Fix the deprecated tag generating invalid PHP for an integer message
This PR was merged into the 3.x branch.
Discussion
----------
Fix the loop variable of a for tag being undefined in the sequence of a nested loop
Commits
-------
0c90971a98 Fix the loop variable of a for tag being undefined in the sequence of a nested loop
This PR was merged into the 3.x branch.
Discussion
----------
Reject the spread operator outside sequences, mappings, and call arguments
Closes#4977
Commits
-------
a04ae6d636 Reject the spread operator outside sequences, mappings, and call arguments
This PR was merged into the 3.x branch.
Discussion
----------
Discard what the non-selected branch of a guard tag registers on the parser
Commits
-------
d5011f4654 Discard what the non-selected branch of a guard tag registers on the parser
This PR was merged into the 3.x branch.
Discussion
----------
Reset the escaping state when compiling a new template after a compilation error
Commits
-------
39642e4cdf Reset the escaping state when compiling a new template after a compilation error
This PR was merged into the 3.x branch.
Discussion
----------
Reject a Template instance created by another environment when resolving templates
Commits
-------
605b1278f7 Reject a Template instance created by another environment when resolving templates
This PR was squashed before being merged into the 3.x branch.
Discussion
----------
3.x doc fixes
Commits
-------
1478f9efcd Fix the class name and a missing parenthesis in the runtime loader example
e883536e64 Replace the deprecated twig_test_even function in the custom test example
db3aeb7379 Use the current variable node class in the node tree example
This PR was merged into the 3.x branch.
Discussion
----------
Fix the autoescape documentation about static expressions
Commits
-------
95a176f2bf Fix the autoescape documentation about static expressions
This PR was merged into the 3.x branch.
Discussion
----------
Fix the sandbox not reporting the line of a rejected guard tag
Commits
-------
b1d6b51183 Fix the sandbox not reporting the line of a rejected guard tag
This PR was merged into the 3.x branch.
Discussion
----------
Use sandbox policy examples that remain meaningful in Twig 4.0
Commits
-------
677f049e64 Use sandbox policy examples that remain meaningful in Twig 4.0
This PR was merged into the 3.x branch.
Discussion
----------
Rewrite the sandbox documentation around what developers need to know
Commits
-------
9d24327f8d Rewrite the sandbox documentation around what developers need to know
This PR was merged into the 3.x branch.
Discussion
----------
Skip the property checker call and memoize the class constant probe when reading an object attribute
Commits
-------
ddd9045b5c Skip the property checker call and memoize the class constant probe when reading an object attribute
This PR was merged into the 3.x branch.
Discussion
----------
Stop looking up a macro twice in its own namespace when it is declared by a parent
Commits
-------
e3f0d6fb4c Stop looking up a macro twice in its own namespace when it is declared by a parent
This PR was merged into the 3.x branch.
Discussion
----------
Fetch the escaper runtime once in the constructor of templates that escape
Commits
-------
3417f483bf Fetch the escaper runtime once in the constructor of templates that escape
This PR was merged into the 3.x branch.
Discussion
----------
Compare the date formatter prototype pattern with the derived one once per pattern
Commits
-------
10fe9808bb Compare the date formatter prototype pattern with the derived one once per pattern
This PR was squashed before being merged into the 3.x branch.
Discussion
----------
Fix split trailing newline
Commits
-------
00861d50ab Fix split trailing newline
This PR was merged into the 3.x branch.
Discussion
----------
Speed up adding extensions to an environment
`Environment::addExtension()` recomputes the options hash on every call, JSON-encoding the class names of all the extensions registered so far. This computes it only when a template class name is needed. With the 24 extensions TwigBundle registers on the Symfony Demo, building the environment drops from 87µs to 19µs, and calling `setExtensions()` once instead brings nothing more.
Merge-up to 4.x: the property is typed there, so it has to become `private ?string $optionsHash = null;` (I ran the 4.x suite with that change). The CHANGELOG entry doesn't go to 4.x.
Commits
-------
d3d13f9b1a Speed up adding extensions to an environment
This PR was merged into the 3.x branch.
Discussion
----------
Reuse the already resolved callable when compiling call arguments
Commits
-------
16be8af8f5 Reuse the already resolved callable when compiling call arguments
This PR was merged into the 3.x branch.
Discussion
----------
Compile the generator guard as an unreachable yield instead of a yield from
Commits
-------
4d5d233776 Compile the generator guard as an unreachable yield instead of a yield from