This PR was squashed before being merged into the 3.x branch.
Discussion
----------
Deprecate internal extension functions in favor of methods on the extension classes
~~PoC on a simple extension for now.~~
Commits
-------
aa7c454e Fix CS
54d34b96 Move functions for CoreExtension
72071e8e Move functions for EscaperExtension
196e91dd Move functions for StringLoaderExtension
d4d01603 Move functions for DebugExtension
69a89e0e Move functions for MarkdownExtension
e07e9b5b Move functions for InkyExtension
bff189f1 Move functions for CssInlinerExtension
6a18cda5 Move functions for HtmlExtension
16abb69d Deprecate internal extension functions in favor of methods on the extension classes
This PR was submitted for the 3.x branch but it was merged into the 2.x branch instead.
Discussion
----------
update Blackfire documentation URL
Update Blackfire documentation's URL in README file
Commits
-------
ed2cfbd6 update Blackfire documentation URL
This PR was merged into the 3.x branch.
Discussion
----------
Fix timezone fallback to CoreExtension in IntlExtension
This is probably a regression from #3844
Refer to my comment on the original MR: https://github.com/twigphp/Twig/pull/3844#issuecomment-1792464040
Commits
-------
144c4dac Fix timezone fallback to CoreExtension in IntlExtension
This PR was merged into the 3.x branch.
Discussion
----------
Minor rename of Sandbox test: functions->methods
Commits
-------
62732646 Minor rename of SandboxTest functions->methods
This PR was merged into the 3.x branch.
Discussion
----------
Removed duplicate sentence in macro scoping
Commits
-------
73f5cad8 Remove duplicate sentence in macro scoping
This PR was squashed before being merged into the 3.x branch.
Discussion
----------
Catch errors thrown during template rendering
Some errors, like not providing a function the proper number of arguments or division by zero, extend from `\Error` rather than `\Exception`. This PR catches these types of errors during template rendering and throws a `RuntimeError` in order to provide better debugging information.
Commits
-------
85bf01b4 Catch errors thrown during template rendering
This PR was merged into the 3.x branch.
Discussion
----------
Add `@codeCoverageIgnore` to untestable compiled methods
I've been experimenting with adding my compiled templates to my code coverage reports and it works largely as expected. Templates that get executed return percentages accurate to the number of lines the tests actually cover. The only exception are the "meta" methods on the compiled template that aren't necessarily called by the tests.
This PR adds ``@codeCoverageIgnore`` comments to the compiled template for all non-display methods so the coverage report only lists lines from `doDisplay`.
I'm assuming that I will need to update some of the Twig tests to account for these new comments, but am curious if you'd be open to this change.
An example screenshot below. The last line shows line 46 out of the compiled template is never executed. The compiled template's `getDebugInfo` even correctly informs me that line 46 maps to line 4 in my `.twig` so I'll work on updating the line numbering next.

Commits
-------
1cf610bd Add `@codeCoverageIgnore` to untestable compiled methods
This PR was squashed before being merged into the 3.x branch.
Discussion
----------
Fix IntlExtension::formatDateTime use of date formatter prototype
See https://github.com/twigphp/intl-extra/pull/6 for more details
Commits
-------
c75762c3 Fix IntlExtension::formatDateTime use of date formatter prototype
This PR was squashed before being merged into the 2.x branch.
Discussion
----------
Fix premature loop exit in Security Policy lookup of allowed methods/properties
The current security policy logic exits too soon when checking permissions for allowed classes and their methods/properties, causing false negatives in situations involving classes related by inheritance.
Consider the following configuration:
```
'methods' => [
'App\BasicCollection' => ['sortAlphabetically'],
'App\AdvancedCollection'=> ['sortByTimestamp'],
],
```
where `AdvancedCollection` is a subclass of `BasicCollection`, and `mylist` is an instance of `AdvancedCollection`
If you try to call `{{ mylist.sortByTimestamp() }}`, the current code will first match `mylist` against `App\BasicCollection`. Since `sortByTimestamp` is not an allowed method for `App\BasicCollection`, the code will exit the loop and incorrectly deny access. It will never get to checking `App\AdvancedCollection`.
Note that reordering classes in the config can't solve this issue. If you flipped the order, then it would fail for `{{ mylist.sortAlphabetically() }}` instead.
This pull request fixes the issue by only exiting the loop early when both the class and method/property match.
Commits
-------
5e1838db Fix premature loop exit in Security Policy lookup of allowed methods/properties
This PR was merged into the 3.x branch.
Discussion
----------
Compile Elvis operator into Elvis operator `?:`
When using ternary operator without "then" part, the "condition" part is evaluated twice, which is inconsistent with how PHP works.
The Twig template `A ?: B` is currently compiled as `A ? A : B` in PHP. This PR change it to `A ?: B`.
If `A` is a complex expression, it improves performance to only execute the expression once.
If `A` is has a side effect (like updating a variable), the expression being executed twice could result in a bug. ([example in PHP](https://3v4l.org/LWZLR))
Example with ``@WebProfiler`/Collector/form.html.twig` [line 9](https://github.com/symfony/symfony/blob/e6d1ed4edb5ae197ec7d25ddaf64cfa456229504/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig#L9) (see deep [diff](https://www.diffchecker.com/jOm3dE13/))
```twig
{{ collector.data.nb_errors ?: collector.data.forms|length }}
```
Previous compilation:
```php
echo twig_escape_filter($this->env, (((isset($context["error_count"]) || array_key_exists("error_count", $context) ? $context["error_count"] : (function () { throw new RuntimeError('Variable "error_count" does not exist.', 9, $this->source); })())) ? ((isset($context["error_count"]) || array_key_exists("error_count", $context) ? $context["error_count"] : (function () { throw new RuntimeError('Variable "error_count" does not exist.', 9, $this->source); })())) : (twig_get_attribute($this->env, $this->source, (isset($context["collector"]) || array_key_exists("collector", $context) ? $context["collector"] : (function () { throw new RuntimeError('Variable "collector" does not exist.', 9, $this->source); })()), "countDefines", [], "any", false, false, false, 9))), "html", null, true);
```
After this change:
```php
echo twig_escape_filter($this->env, ((isset($context["error_count"]) || array_key_exists("error_count", $context) ? $context["error_count"] : (function () { throw new RuntimeError('Variable "error_count" does not exist.', 9, $this->source); })()) ?: twig_get_attribute($this->env, $this->source, (isset($context["collector"]) || array_key_exists("collector", $context) ? $context["collector"] : (function () { throw new RuntimeError('Variable "collector" does not exist.', 9, $this->source); })()), "countDefines", [], "any", false, false, false, 9)), "html", null, true);
```
Commits
-------
fb0d7495 Compile Elvis operator with Elvis operator
This PR was merged into the 3.x branch.
Discussion
----------
Update signature to acknowledge a TemplateWrapper
`$name` legitimately can be of type `Twig\TemplateWrapper`. This is already considered in line 1331. This PR updates the method signature in the PHPDoc.
This PR is necessary because other developers may rely on the signature, see contao/contao#6169.
Commits
-------
b0cabc09 Update signature to acknowledge a TemplateWrapper
This PR was merged into the 3.x branch.
Discussion
----------
Use PHP 8.0 functions with polyfill
Backport some changes from #3881 into 3.x using `symfony/polyfill-php80`.
- `str_starts_with`
- `str_ends_with`
- `str_contains`
- `get_debug_type`
Benefits:
- Less conflicts when both 3.x and 4.x branches will be maintained.
- Performance gain for PHP 8.0+ ([83,7% of installs](https://packagist.org/packages/twig/twig/php-stats#3))
Commits
-------
1d5c0928 Use PHP 8.0 functions with polyfill
This PR was squashed before being merged into the 3.x branch.
Discussion
----------
Use PHP 7.1 features : `is_iterable`, `??` and `?:`
Apply the following changes with rector, compatible with PHP 7.1:
```php
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths([
__DIR__ . '/src',
__DIR__ . '/doc',
__DIR__ . '/tests',
__DIR__ . '/extra',
]);
$rectorConfig->rule(\Rector\Php53\Rector\Ternary\TernaryToElvisRector::class);
$rectorConfig->rule(\Rector\Php70\Rector\Ternary\TernaryToNullCoalescingRector::class);
$rectorConfig->rule(\Rector\Php71\Rector\BooleanOr\IsIterableRector::class);
};
```
Commits
-------
991f518d Replace calls to twig_test_iterable to is_iterable
6ca0d773 Convert Ternary to Elvis or Null Coalescing
cb8a8247 Use is_iterable when possible