Skip to content

SimplifyEmptyCheckOnEmptyArrayRector rewrites empty() on a possibly-undefined variable, introducing a warning and changing behavior #9768

@dereuromark

Description

@dereuromark

Bug Report

Subject Details
Rector version 2.4.4
PHP version 8.4.21

SimplifyEmptyCheckOnEmptyArrayRector rewrites empty($var) to $var === []. These are only equivalent when $var is guaranteed to be a defined array.

empty() tolerates an undefined variable (no warning, evaluates to true); $var === [] does not — on an undefined variable PHP emits Warning: Undefined variable $var and evaluates null === [], i.e. false. The result therefore flips on the undefined path. The rule currently applies even when the variable is only conditionally defined.

This is the same class of "the rule should be skipped because it introduces an error" problem as #9315 (closed/fixed for the is_array() + complex-expression case), but the possibly-undefined plain-variable case still reproduces on 2.4.4.

Minimal PHP Code Causing Issue

<?php
namespace My\App;

class Demo
{
    public function run(bool $cond): array
    {
        if ($cond) {
            $map = ['a' => 1];
        }

        // empty() tolerates an undefined $map; `$map === []` does not.
        if (empty($map)) {
            return [];
        }

        return $map;
    }
}

Config:

use Rector\CodeQuality\Rector\Empty_\SimplifyEmptyCheckOnEmptyArrayRector;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withRules([SimplifyEmptyCheckOnEmptyArrayRector::class]);

Result:

-        if (empty($map)) {
+        if ($map === []) {

When $cond is false, $map is never defined:

  • before: empty($map)true → returns []
  • after: $map === []Warning: Undefined variable $map and null === []false → falls through

Expected Behaviour

Skip the rewrite when the variable is not guaranteed to be defined (only conditionally assigned), consistent with the error-avoidance fix in #9315.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions