Variable Variables

ID

php.variable_variables

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Complexity

Language

Php

Tags

best-practice, complexity

Description

A variable whose name is decided at run time: $$field, ${$field}, ${'prefix_' . $field}, or an extract() call that creates a whole set of them out of an array.

A variable variable is invisible to every reader and every tool. Nothing can say where $total was written, because it may have been written as $$name; nothing can say whether a name is still in use, so dead code accumulates; an IDE cannot rename it, and a security analysis cannot follow the value through it. When the computed name comes from request data, the assignment also writes over whatever local happened to share that name.

Rationale

public function bind(array $row, string $field): void
{
    $$field = $row[$field];       // which variable is this?
    ${'prefix_' . $field} = 'y';  // and this?

    extract($row);                // one local per array key, names unknown until run time

    // ... 40 lines later, $total is used. Was it ever assigned? Nobody can say.
}

The reader cannot answer any question about the local scope any more, and neither can grep, an IDE, or a static analyzer.

Remediation

Store the values in an array, whose keys are data and stay data.

public function bind(array $row, string $field): void
{
    $values = [];
    $values[$field] = $row[$field];
    $values['prefix_' . $field] = 'y';

    $this->apply($values);
}

Where the set of names is fixed, name them:

$total = $row['total'];
$label = $row['label'];

Only the variable forms are reported. Dynamic member access ($model→$field), dynamic calls ($model→{$field}(), $callable($x)) and dynamic instantiation (new $class()) are out of scope: they are how ORMs, serializers, containers and event dispatchers are written, and they do not create names out of thin air. compact() is out for the same reason — it reads variables that are written literally somewhere above, so the names stay greppable.

"${name}" inside a double-quoted string is string interpolation, not a variable variable, and is never reported.

© 2026 Xygeni. All rights reserved