Usare <code>$GLOBALS</code> in PHP senza perdere il controllo dello stato globale

by theArchitect
SHARE
Usare <code>$GLOBALS</code> in PHP senza perdere il controllo dello stato globale
© Guida-HTML5.it

Introduzione

In PHP, le superglobali sono variabili disponibili in qualsiasi punto dello script, anche dentro funzioni e metodi, senza doverle dichiarare con la parola chiave global. Tra queste variabili c’è $GLOBALS, un array associativo che contiene tutti i nomi delle variabili globali definite nello script.

$GLOBALS può essere utile in piccoli script procedurali, negli strumenti di diagnostica e durante il refactoring di codice legacy. Tuttavia, usarla per condividere liberamente dati tra tutte le funzioni può rendere l’applicazione difficile da comprendere e testare. Per questo motivo è importante conoscerne il funzionamento, ma anche applicare alcune regole per limitarne gli effetti collaterali.

In questo tutorial costruiremo un semplice contatore globale, lo aggiorneremo da una funzione e analizzeremo un approccio più ordinato basato sul passaggio esplicito dei parametri.

Codice completo

<?php
declare(strict_types=1);

/*
 * Variabile globale inizializzata nel contesto principale dello script.
 * Sarà accessibile anche tramite $GLOBALS[´contatore´].
 */
$contatore = 0;

/*
 * Elenco globale delle operazioni eseguite.
 * È preferibile mantenere una struttura dati ben definita,
 * invece di creare molte variabili globali indipendenti.
 */
$registroOperazioni = [];

/**
 * Incrementa il contatore usando la superglobale $GLOBALS.
 *
 * @param int $quantita Numero di unità da aggiungere
 */
function aggiungiOperazioni(int $quantita): void
{
    if ($quantita < 1) {
        throw new InvalidArgumentException(
            ´La quantità deve essere maggiore di zero.´
        );
    }

    // Accesso diretto alla variabile globale tramite il suo nome.
    $GLOBALS[´contatore´] += $quantita;

    // Aggiornamento di un secondo valore globale.
    $GLOBALS[´registroOperazioni´][] = [
        ´quantita´ => $quantita,
        ´totale´ => $GLOBALS[´contatore´],
    ];
}

/**
 * Restituisce un riepilogo dello stato globale.
 *
 * @return array<string, mixed>
 */
function creaRiepilogo(): array
{
    return [
        ´totale´ => $GLOBALS[´contatore´],
        ´operazioni´ => count($GLOBALS[´registroOperazioni´]),
    ];
}

try {
    aggiungiOperazioni(3);
    aggiungiOperazioni(2);

    $riepilogo = creaRiepilogo();

    echo ´<h1>Riepilogo operazioni</h1>´;
    echo ´<p>Totale: ´ . $riepilogo[´totale´] . ´</p>´;
    echo ´<p>Operazioni registrate: ´ .
        $riepilogo[´operazioni´] . ´</p>´;

    echo ´<pre>´;
    echo htmlspecialchars(
        print_r($GLOBALS[´registroOperazioni´], true),
        ENT_QUOTES,
        ´UTF-8´
    );
    echo ´</pre>´;
} catch (InvalidArgumentException $exception) {
    echo ´Errore: ´ . htmlspecialchars(
        $exception->getMessage(),
        ENT_QUOTES,
        ´UTF-8´
    );
}

Spiegazione

Come funziona $GLOBALS

Quando definiamo una variabile fuori da una funzione, questa appartiene allo scope globale dello script. Una funzione, però, possiede normalmente un proprio scope locale e non può usare direttamente quella variabile.

Per esempio, questo codice non funziona come spesso si potrebbe immaginare:

<?php
$totale = 10;

function mostraTotale(): void
{
    // $totale non è disponibile automaticamente qui.
    echo $totale;
}

Con $GLOBALS, invece, possiamo accedere alla variabile usando il suo nome come chiave:

<?php
$totale = 10;

function mostraTotale(): void
{
    echo $GLOBALS[´totale´];
}

mostraTotale(); // Stampa 10

È importante ricordare che $GLOBALS[´totale´] e la variabile $totale fanno riferimento allo stesso valore globale. Se modifichiamo il primo, modifichiamo anche il secondo.

Confronto con la parola chiave global

Un’alternativa è dichiarare la variabile con global all’interno della funzione:

<?php
$messaggio = ´Operazione completata´;

function stampaMessaggio(): void
{
    global $messaggio;

    echo $messaggio;
}

Le due tecniche hanno un risultato simile, ma $GLOBALS rende esplicito il fatto che stiamo leggendo o modificando una variabile globale tramite un array. Questa caratteristica può essere utile in codice dinamico, ma non elimina i rischi legati allo stato condiviso.

Il problema delle modifiche imprevedibili

Se molte funzioni modificano le stesse chiavi di $GLOBALS, diventa difficile capire quale funzione abbia cambiato un valore. Inoltre, i test automatici possono diventare fragili perché una funzione potrebbe dipendere da dati lasciati da una precedente esecuzione.

Un approccio più sicuro consiste nel passare i dati come parametri e restituire un risultato:

<?php
function aggiungi(int $totale, int $quantita): int
{
    if ($quantita < 1) {
        throw new InvalidArgumentException(´Quantità non valida.´);
    }

    return $totale + $quantita;
}

$totale = aggiungi(0, 3);
$totale = aggiungi($totale, 2);

echo $totale; // 5

Best practice

  • Limita l’uso di $GLOBALS: preferisci parametri, valori restituiti e oggetti con responsabilità definite.
  • Usa nomi chiari: se devi accedere a una variabile globale, scegli chiavi descrittive come configurazioneApp o registroOperazioni.
  • Non inserire dati provenienti direttamente dall’utente: una superglobale non rende automaticamente sicuri i valori contenuti.
  • Evita di salvare segreti in variabili globali: password, token e chiavi private devono essere gestiti con particolare attenzione.
  • Valida i dati prima di modificarli: nell’esempio controlliamo che la quantità sia un intero positivo.
  • Proteggi l’output HTML: quando visualizzi dati dinamici, utilizza htmlspecialchars() per ridurre il rischio di XSS.
  • Preferisci funzioni pure nei componenti riutilizzabili: una funzione che riceve input e restituisce output è più semplice da testare.

Riepilogo

$GLOBALS è una superglobale che permette di accedere alle variabili dello scope globale da qualunque funzione. È semplice da usare e può essere utile in script piccoli o durante la manutenzione di applicazioni legacy.

Il suo principale svantaggio è lo stato condiviso: più parti del programma possono leggere e modificare gli stessi dati, creando dipendenze nascoste. Nei progetti moderni è generalmente preferibile passare i valori tramite parametri, usare classi e mantenere le responsabilità ben separate.

Approfondisci con risorse ufficiali

SHARE