minor #4662 CoreExtension::getAttribute: small improvement regarding getter/isser/hasser (gharlan)

This PR was merged into the 3.x branch.

Discussion
----------

CoreExtension::getAttribute: small improvement regarding getter/isser/hasser

For a getter method like `getFirstName` it is common to call it in twig via `person.firstName`.
But at the moment twig is adding these variants to the class method cache: `getFirstName`, `getfirstname`, `FirstName` and `firstname`.
So when resolving the name, it uses the first `elseif` here with additional `strtolower` call, because `firstName` is missing:

https://github.com/twigphp/Twig/blob/403bd9d73c2a010e5b26689f2f2eb9d7ddf391af/src/Extension/CoreExtension.php#L1863-L1867

This PR replaces `FirstName` with `firstName` in the method cache.
So `person.firstName` is resolved via first `if` branch (but `person.FirstName` would use the `elseif` with `strtolower` now).

Commits
-------

45cd6ffe80 CoreExtension::getAttribute: small improvement regarding getter/isser/hasser
This commit is contained in:
Fabien Potencier
2026-06-04 22:28:58 +02:00
+11 -8
View File
@@ -1843,14 +1843,14 @@ final class CoreExtension extends AbstractExtension
$classCache[$lcName = $lcMethods[$i]] = $method;
if ('g' === $lcName[0] && str_starts_with($lcName, 'get')) {
$name = substr($method, 3);
$lcName = substr($lcName, 3);
$prefixLength = 3;
$lcName = substr($lcName, $prefixLength);
} elseif ('i' === $lcName[0] && str_starts_with($lcName, 'is')) {
$name = substr($method, 2);
$lcName = substr($lcName, 2);
$prefixLength = 2;
$lcName = substr($lcName, $prefixLength);
} elseif ('h' === $lcName[0] && str_starts_with($lcName, 'has')) {
$name = substr($method, 3);
$lcName = substr($lcName, 3);
$prefixLength = 3;
$lcName = substr($lcName, $prefixLength);
if (\in_array('is'.$lcName, $lcMethods, true)) {
continue;
}
@@ -1858,8 +1858,11 @@ final class CoreExtension extends AbstractExtension
continue;
}
// skip get() and is() methods (in which case, $name is empty)
if ($name) {
// skip get(), is() and has() methods (in which case, $lcName is empty)
if ($lcName) {
// camelCase name (e.g. getFooBar() -> fooBar)
$name = $lcName[0].substr($method, $prefixLength + 1);
if (!isset($classCache[$name])) {
$classCache[$name] = $method;
}