Funzioni PHP con parametri per riferimento: modificare i dati in modo consapevole

by theArchitect
SHARE
Funzioni PHP con parametri per riferimento: modificare i dati in modo consapevole
© Guida-HTML5.it

Introduzione

In PHP una funzione riceve normalmente una copia del valore passato come argomento. Questo comportamento è sicuro e prevedibile: se la funzione modifica il parametro, la variabile originale che si trova all’esterno non cambia. In alcuni casi, però, può essere utile permettere a una funzione di modificare direttamente una variabile del chiamante. Per ottenere questo risultato si usa il passaggio per riferimento, indicato con il simbolo &.

Il passaggio per riferimento è pratico quando una funzione deve aggiornare più valori, restituire un risultato aggiuntivo oppure lavorare su una struttura dati senza creare una copia logica del suo contenuto. Tuttavia, deve essere utilizzato con attenzione: una funzione che modifica direttamente i propri argomenti può essere meno facile da comprendere e da testare.

In questo tutorial costruiremo un esempio reale: una funzione che analizza un ordine e aggiorna due variabili, il totale dell’ordine e il numero di articoli elaborati. Vedremo la sintassi, le differenze rispetto al normale passaggio per valore e le buone pratiche da applicare nei progetti PHP moderni.

Codice completo

<?php

/**
 * Calcola il totale di un ordine e conta gli articoli validi.
 *
 * I parametri $totale e $articoliElaborati sono passati per riferimento:
 * la funzione può quindi modificarli direttamente.
 *
 * @param array $prodotti
 * @param float $totale
 * @param int $articoliElaborati
 * @return void
 */
function analizzaOrdine(
    array $prodotti,
    float &$totale,
    int &$articoliElaborati
): void {
    $totale = 0.0;
    $articoliElaborati = 0;

    foreach ($prodotti as $prodotto) {
        // Ignoriamo elementi incompleti o non validi.
        if (
            !isset($prodotto[´nome´], $prodotto[´prezzo´], $prodotto[´quantita´]) ||
            $prodotto[´prezzo´] < 0 ||
            $prodotto[´quantita´] <= 0
        ) {
            continue;
        }

        $totale += $prodotto[´prezzo´] * $prodotto[´quantita´];
        $articoliElaborati += $prodotto[´quantita´];
    }
}

$ordine = [
    [
        ´nome´ => ´Tastiera´,
        ´prezzo´ => 49.90,
        ´quantita´ => 1
    ],
    [
        ´nome´ => ´Mouse´,
        ´prezzo´ => 24.50,
        ´quantita´ => 2
    ],
    [
        ´nome´ => ´Cavo non valido´,
        ´prezzo´ => -5.00,
        ´quantita´ => 1
    ]
];

$totaleOrdine = 0.0;
$numeroArticoli = 0;

analizzaOrdine($ordine, $totaleOrdine, $numeroArticoli);

echo "Totale ordine: " . number_format($totaleOrdine, 2, ´,´, ´.´) . " euro" . PHP_EOL;
echo "Articoli elaborati: " . $numeroArticoli . PHP_EOL;

// Output:
// Totale ordine: 98,90 euro
// Articoli elaborati: 3

Spiegazione

Passaggio normale per valore

Consideriamo una funzione che riceve un numero senza il simbolo &:

<?php

function applicaSconto(float $prezzo): void
{
    $prezzo = $prezzo * 0.90;
}

$prezzoOriginale = 100.00;

applicaSconto($prezzoOriginale);

echo $prezzoOriginale; // 100

La variabile $prezzoOriginale rimane invariata. La funzione lavora sul parametro locale $prezzo, che rappresenta il valore ricevuto, ma non modifica direttamente la variabile esterna.

Passaggio per riferimento

Aggiungendo & nella dichiarazione del parametro, la funzione riceve un riferimento alla variabile originale:

<?php

function applicaScontoDiretto(float &$prezzo): void
{
    $prezzo = $prezzo * 0.90;
}

$prezzoOriginale = 100.00;

applicaScontoDiretto($prezzoOriginale);

echo $prezzoOriginale; // 90

In questo caso $prezzo e $prezzoOriginale indicano lo stesso dato. Ogni modifica eseguita nella funzione sarà visibile anche dopo la chiamata.

Quando è utile

Il riferimento può essere utile quando una funzione deve produrre più risultati. PHP permette di restituire un solo valore con return, ma una funzione può aggiornare più parametri passati per riferimento. Nel codice completo, analizzaOrdine() aggiorna sia $totale sia $articoliElaborati.

È importante ricordare che bisogna passare una vera variabile. Non è corretto fornire direttamente un’espressione o un valore letterale:

<?php

function incrementa(int &$numero): void
{
    $numero++;
}

$valore = 10;
incrementa($valore); // Corretto

// incrementa(10); // Errore: 10 non è una variabile modificabile

Una possibile alternativa

Spesso è più leggibile restituire un array associativo con tutti i risultati. In questo modo la funzione non modifica dati esterni:

<?php

function calcolaOrdine(array $prodotti): array
{
    $totale = 0.0;
    $articoli = 0;

    foreach ($prodotti as $prodotto) {
        if ($prodotto[´prezzo´] >= 0 && $prodotto[´quantita´] > 0) {
            $totale += $prodotto[´prezzo´] * $prodotto[´quantita´];
            $articoli += $prodotto[´quantita´];
        }
    }

    return [
        ´totale´ => $totale,
        ´articoli´ => $articoli
    ];
}

$risultato = calcolaOrdine($ordine);

echo $risultato[´totale´];

Questa soluzione è spesso preferibile perché rende esplicito il risultato e riduce gli effetti collaterali.

Best practice

  • Usa il riferimento solo quando serve davvero: non aggiungere & automaticamente. Se una funzione può restituire il risultato con return, questa soluzione è generalmente più chiara.
  • Dichiara i tipi: indicare float, int, array e void rende il contratto della funzione più comprensibile.
  • Documenta la modifica: specifica nel commento PHPDoc quali parametri vengono aggiornati dalla funzione.
  • Evita modifiche imprevedibili: una funzione dovrebbe modificare soltanto i riferimenti chiaramente indicati e non intervenire su variabili globali.
  • Valuta gli array di ritorno: se i risultati sono numerosi, un array associativo o un oggetto dedicato può essere più leggibile di molti parametri per riferimento.
  • Testa gli effetti collaterali: verifica sia il valore restituito sia il nuovo contenuto delle variabili passate per riferimento.
  • Non confondere riferimento e modifica degli array: gli array PHP hanno regole proprie di copia su scrittura. Il simbolo & indica esplicitamente che la funzione condivide la variabile originale.

Riepilogo

Il passaggio per riferimento permette a una funzione PHP di modificare direttamente una variabile esterna. Si ottiene aggiungendo & davanti al tipo o al nome del parametro, ad esempio int &$contatore. È una tecnica utile per aggiornare più valori durante una singola operazione, ma introduce un effetto collaterale che deve essere documentato e controllato.

Per codice semplice e prevedibile, preferisci normalmente il ritorno di un valore, di un array associativo o di un oggetto. Usa i riferimenti quando rappresentano chiaramente l’intenzione dell’API della funzione e quando il vantaggio pratico supera la maggiore complessità.

Approfondisci con risorse ufficiali

SHARE