Aikido

Perché dovresti evitare i nomi di variabili dinamici in PHP

Leggibilità

Regola
Evita nomi di variabili dinamici
I nomi di variabili dinamici (variable variables) possono portare
a codice difficile da manutenere e a comportamenti inattesi. 
Il loro utilizzo è solitamente il risultato di un errore di battitura.

Linguaggi supportati: PHP

Introduzione

La funzionalità delle variabili di variabili in PHP consente di usare il valore di una variabile come nome di un'altra variabile tramite la $$ sintassi. Quella che sembra una comoda scorciatoia si trasforma in un incubo di debugging quando non è possibile determinare staticamente quali variabili esistono o cosa contengono. Il codice che utilizza $$userName al posto di un array o della proprietà di un oggetto impedisce agli IDE di fornire l'autocompletamento, agli analizzatori statici di intercettare i bug e agli sviluppatori di tracciare il flusso dei dati all'interno dell'applicazione.

Perché è importante

Manutenibilità del codice: Le variabili di variabili compromettono qualsiasi strumento su cui fanno affidamento gli sviluppatori. Gli IDE non possono autocompletare i nomi delle variabili, trovare gli utilizzi o effettuare refactoring in sicurezza. Gli strumenti di analisi statica non sono in grado di rilevare variabili non definite o problemi di corrispondenza dei tipi. Il debugging richiede un'ispezione a runtime, poiché non è possibile eseguire il grep sulla codebase per individuare dove le variabili vengono impostate o lette.

Implicazioni di sicurezza: Quando i nomi delle variabili di variabili derivano da input utente, gli attaccanti possono sovrascrivere variabili arbitrarie, incluse quelle critiche per la sicurezza. Un parametro di richiesta malevolo potrebbe prendere di mira $$_GET['var'] per sovrascrivere $isAdmin, $userId, oppure le variabili di sessione. Questo genera vulnerabilità di iniezione di variabili che risultano difficili da rilevare e facili da sfruttare.

Impatto sulle prestazioni: Le variabili di variabili costringono PHP a eseguire ricerche a runtime anziché la risoluzione dei simboli in fase di compilazione. L'interprete deve valutare dinamicamente il nome della variabile a ogni accesso, impedendo le ottimizzazioni applicabili alle variabili normali. Array e oggetti offrono funzionalità simili con caratteristiche di performance superiori.

Esempi di codice

❌ Non conforme:

function processFormData($formType) {
    $userForm = ['name' => '', 'email' => ''];
    $adminForm = ['name' => '', 'email' => '', 'role' => ''];

    $formName = $formType . 'Form';
    $$formName = array_merge($$formName, $_POST);

    if ($$formName['email']) {
        sendEmail($$formName['email']);
    }

    return $$formName;
}

// What variable does this actually use?
processFormData('user');

Perché è errato: Il codice crea $userForm o $adminForm in modo dinamico usando $$formName, rendendo impossibile tracciare quale variabile venga modificata. Se $formType proviene dall'input dell'utente, gli attaccanti potrebbero iniettare nomi di variabili arbitrari per sovrascrivere variabili critiche.

✅ Conforme:

function processFormData(string $formType): array {
    $forms = [
        'user' => ['name' => '', 'email' => ''],
        'admin' => ['name' => '', 'email' => '', 'role' => '']
    ];

    if (!isset($forms[$formType])) {
        throw new InvalidArgumentException('Invalid form type');
    }

    $form = array_merge($forms[$formType], $_POST);

    if (!empty($form['email'])) {
        sendEmail($form['email']);
    }

    return $form;
}

// Clear which data structure is being used
processFormData('user');

Perché è importante: Il codice utilizza un array esplicito con chiavi note, rendendo evidente il flusso dei dati e abilitando tutte le funzionalità degli IDE. La validazione dell'input previene gli attacchi di iniezione e l'analisi statica può verificare la correttezza del codice.

Conclusione

Sostituisci le variabili di variabili con array, oggetti o una migliore struttura del codice. Usa gli array quando ti serve l'accesso a chiavi dinamiche, gli oggetti per dati strutturati con proprietà note ed effettua il refactoring della logica duplicata in astrazioni adeguate. Le variabili di variabili indicano quasi sempre un problema di progettazione che strutture dati appropriate risolverebbero in modo più chiaro.

FAQ

Hai domande?

Ci sono usi legittimi per le variabili di variabili?

Estremamente rari. I motori di template e i framework di metaprogrammazione a volte le utilizzano, ma anche in questi casi è preferibile affidarsi ad array o strutture dati dedicate. Se pensi di aver bisogno di variabili di variabili, probabilmente ti serve un array con chiavi dinamiche o una riprogettazione del flusso dei dati.

Che dire di extract() che crea variabili in modo dinamico?

Evita extract() per gli stessi motivi delle variabili variabili. Crea variabili da chiavi di array in modo dinamico, compromettendo l'analisi statica e introducendo rischi per la sicurezza. Usa direttamente l'accesso agli array: $data['key'] anziché extract($data); $key. Il codice PHP moderno dovrebbe considerare extract() come uno "smell" di codice.

Come posso effettuare il refactoring del codice esistente che utilizza le variabili variabili?

Identifica il pattern che viene implementato. Di solito si tratta di dati di configurazione (usa gli array), proprietà dinamiche (usa oggetti o array) o logica condizionale (usa strutture di controllo adeguate). Sostituisci $$varName con $config[$varName] nella maggior parte dei casi. Usa gli oggetti quando hai bisogno di type safety e del supporto dell'IDE per l'accesso alle proprietà.

Che dire dell'uso di variabili variabili per le costanti?

È comunque problematico. Usa constant($name) se devi accedere dinamicamente alle costanti, sebbene questo suggerisca anche un problema di progettazione. Un approccio migliore: organizza le costanti correlate in una classe e usa un array o un'espressione match per selezionare il valore appropriato in base alle condizioni di runtime.

Le variabili variabili possono causare conflitti di namespace?

Sì, soprattutto con le superglobali e le variabili dei framework. Il codice che utilizza $$type = 'value' potrebbe creare accidentalmente $_GET, $_POST o variabili di framework come $this in contesti inattesi. Gli array inseriscono naturalmente i loro dati in un namespace, prevenendo questi conflitti per progettazione.

Metti in sicurezza ora

Metti in sicurezza il tuo codice, il cloud e il runtime in un unico sistema centralizzato.
Trova e risolvi le vulnerabilità rapidamente e automaticamente.

Nessuna carta di credito richiesta | Risultati della scansione in 32 secondi.