Skip to content

Support short-circuiting in null-safe operator chains#4748

Merged
fabpot merged 1 commit intotwigphp:3.xfrom
HypeMC:short-circuiting-in-null-safe-operator-chains
Feb 8, 2026
Merged

Support short-circuiting in null-safe operator chains#4748
fabpot merged 1 commit intotwigphp:3.xfrom
HypeMC:short-circuiting-in-null-safe-operator-chains

Conversation

@HypeMC
Copy link
Copy Markdown
Contributor

@HypeMC HypeMC commented Jan 25, 2026

This PR adds short-circuiting for null-safe operator chains, using the same rules as PHP, PropertyAccess, and the ExpressionLanguage.

Previously, only the immediate null-safe access was guarded. With this change, as soon as a null is encountered at a null-safe access, the rest of the chain is skipped.

My approach was to move the null check outside of the getAttribute() calls so the expression can immediately return null, eg:

foo?.bar.baz

Before:

yield $this->env
    ->getRuntime('Twig\Runtime\EscaperRuntime')
    ->escape(
        CoreExtension::getAttribute(
            $this->env,
            $this->source,
            (
                null === (
                    $_v0 = (
                        isset($context['foo']) || array_key_exists('foo', $context)
                            ? $context['foo']
                            : throw new RuntimeError('Variable "foo" does not exist.', 3, $this->source)
                    )
                )
                    ? null
                    : CoreExtension::getAttribute(
                        $this->env,
                        $this->source,
                        $_v0,
                        'bar',
                        [],
                        'any',
                        false,
                        false,
                        false,
                        3
                    )
            ),
            'baz',
            [],
            'any',
            false,
            false,
            false,
            3
        ),
        'html',
        null,
        true
    );

Now:

yield $this->env
    ->getRuntime('Twig\Runtime\EscaperRuntime')
    ->escape(
        (
            null === (
                $_v0 = (
                    isset($context['foo']) || array_key_exists('foo', $context)
                        ? $context['foo']
                        : throw new RuntimeError('Variable "foo" does not exist.', 3, $this->source)
                )
            )
                ? null
                : CoreExtension::getAttribute(
                    $this->env,
                    $this->source,
                    CoreExtension::getAttribute(
                        $this->env,
                        $this->source,
                        $_v0,
                        'bar',
                        [],
                        'any',
                        false,
                        false,
                        false,
                        3
                    ),
                    'baz',
                    [],
                    'any',
                    false,
                    false,
                    false,
                    3
                )
        ),
        'html',
        null,
        true
    );

fabpot added a commit that referenced this pull request Jan 27, 2026
This PR was merged into the 3.x branch.

Discussion
----------

Fix null-safe operator test

Noticed this while working on #4748.

Without `strict_variables`, the tests always pass, even when the null-safe operator is not used.

Commits
-------

a16ac6b Fix null-safe operator test
@HypeMC HypeMC force-pushed the short-circuiting-in-null-safe-operator-chains branch from e8db373 to 4375ed6 Compare January 29, 2026 14:00
@HypeMC HypeMC force-pushed the short-circuiting-in-null-safe-operator-chains branch from 4375ed6 to d56e8e2 Compare February 6, 2026 21:37
@fabpot
Copy link
Copy Markdown
Contributor

fabpot commented Feb 8, 2026

Thank you @HypeMC.

@fabpot fabpot merged commit 751a187 into twigphp:3.x Feb 8, 2026
40 of 41 checks passed
@HypeMC HypeMC deleted the short-circuiting-in-null-safe-operator-chains branch February 8, 2026 19:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants