Skip to content

[CodeQuality] Skip short-circuit dependent values on RepeatedAndNotEqualToNotInArrayRector and RepeatedOrEqualToInArrayRector - #8516

Merged
TomasVotruba merged 1 commit into
rectorphp:mainfrom
guillaume-sainthillier:skip-short-circuit-dependent-in-array
Sep 23, 2026
Merged

TomasVotruba merged 1 commit into
rectorphp:mainfrom
guillaume-sainthillier:skip-short-circuit-dependent-in-array

Conversation

@guillaume-sainthillier

Copy link
Copy Markdown
Contributor

RepeatedAndNotEqualToNotInArrayRector rewrote a chain of null checks where later operands depend on earlier ones:

if (null !== $locale && null !== $translations && null !== $translations->getTranslation($locale))

into

if (!in_array(null, [$locale, $translations, $translations->getTranslation($locale)], true))

The array literal evaluates every item up front, while && stops at the first failing compare. getTranslation() now runs on a null $translations and, with a null $locale, receives an argument its string param does not accept. A nullsafe ?-> would only cover the first case, so the chain has to stay as is. RepeatedOrEqualToInArrayRector had the same issue with ||.

Both rules build the array in InArrayFromRepeatedCompareFactory, which now only accepts values that are safe to evaluate eagerly: plain variables, plus what ExprAnalyzer::isDynamicExpr() already treats as static (scalars, constants, class constants, constant arrays). Method calls, property and array fetches, and $$name keep the original chain.

The compared expression is not restricted: the chain always evaluates it at least once and in_array() evaluates it exactly once.

Fixtures, for each rule:

  • skip_short_circuit_dependent_call.php.inc: the case above stays unchanged
  • yoda_null_on_variables.php.inc: null !== $a && null !== $b && null !== $c still becomes !in_array(null, [$a, $b, $c], true)

…ualToNotInArrayRector and RepeatedOrEqualToInArrayRector

A repeated null check where later operands rely on earlier ones:

    null !== $locale && null !== $translations && null !== $translations->getTranslation($locale)

became

    !in_array(null, [$locale, $translations, $translations->getTranslation($locale)], true)

The array literal evaluates every item up front, while && stops at the
first failing compare, so getTranslation() now runs on a null
$translations, or with a null $locale it does not accept. The || variant
in RepeatedOrEqualToInArrayRector had the same issue.

Both rules build the array in InArrayFromRepeatedCompareFactory, which now
only accepts values that are safe to evaluate eagerly: plain variables,
scalars, constants, class constants and constant arrays. Calls, property
and array fetches keep the chain as is.

@samsonasik samsonasik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good 👍

@TomasVotruba
TomasVotruba merged commit ec9f135 into rectorphp:main Sep 23, 2026
45 checks passed
@TomasVotruba

Copy link
Copy Markdown
Member

Thanks

@guillaume-sainthillier
guillaume-sainthillier deleted the skip-short-circuit-dependent-in-array branch September 23, 2026 16:42
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.

3 participants