Gestire gli argomenti da riga di comando con <code>$argc</code> e <code>$argv</code> in PHP

by theArchitect
SHARE
Gestire gli argomenti da riga di comando con <code>$argc</code> e <code>$argv</code> in PHP
© Guida-HTML5.it

Introduzione

Quando si parla di superglobali PHP, l’attenzione va spesso verso $_GET, $_POST o $_SERVER. Tuttavia, PHP mette a disposizione anche due variabili molto utili per gli script eseguiti da terminale: $argc e $argv.

$argc contiene il numero degli argomenti passati allo script, mentre $argv è un array che conserva i singoli valori ricevuti. Queste variabili sono disponibili principalmente nel contesto CLI, cioè quando eseguiamo PHP dal prompt dei comandi:

php report.php --formato=csv --mese=10

In questo scenario, $argv[0] contiene il nome dello script, mentre gli elementi successivi rappresentano gli argomenti forniti dall’utente. È una tecnica pratica per creare comandi di manutenzione, importazione dati, esportazione di report e operazioni pianificate tramite cron.

Codice completo

Il seguente esempio realizza un comando CLI che accetta tre opzioni:

  • --formato, con valore csv oppure json;
  • --mese, con un numero compreso tra 1 e 12;
  • --dettagli, un’opzione senza valore.
<?php

declare(strict_types=1);

/**
 * Mostra le istruzioni d´uso del comando.
 */
function mostraAiuto(): void
{
    echo <<<TESTO
Uso:
  php report.php [opzioni]

Opzioni:
  --formato=csv|json   Formato del report, predefinito: json
  --mese=1..12         Mese da analizzare, predefinito: mese corrente
  --dettagli           Mostra informazioni aggiuntive
  --help               Mostra questo aiuto

TESTO;
}

/**
 * Converte gli argomenti ricevuti in una configurazione.
 *
 * @param array<int, string> $argomenti
 * @return array{formato: string, mese: int, dettagli: bool}
 */
function leggiOpzioni(array $argomenti): array
{
    $configurazione = [
        ´formato´ => ´json´,
        ´mese´ => (int) date(´n´),
        ´dettagli´ => false,
    ];

    // Ignoriamo $argomenti[0], che contiene il nome dello script.
    foreach (array_slice($argomenti, 1) as $argomento) {
        if ($argomento === ´--help´) {
            mostraAiuto();
            exit(0);
        }

        if ($argomento === ´--dettagli´) {
            $configurazione[´dettagli´] = true;
            continue;
        }

        if (str_starts_with($argomento, ´--formato=´)) {
            $formato = substr($argomento, strlen(´--formato=´));

            if (!in_array($formato, [´csv´, ´json´], true)) {
                throw new InvalidArgumentException(
                    ´Il formato deve essere csv oppure json.´
                );
            }

            $configurazione[´formato´] = $formato;
            continue;
        }

        if (str_starts_with($argomento, ´--mese=´)) {
            $mese = substr($argomento, strlen(´--mese=´));

            if (!ctype_digit($mese) || (int) $mese < 1 || (int) $mese > 12) {
                throw new InvalidArgumentException(
                    ´Il mese deve essere un numero compreso tra 1 e 12.´
                );
            }

            $configurazione[´mese´] = (int) $mese;
            continue;
        }

        throw new InvalidArgumentException(
            "Opzione non riconosciuta: {$argomento}"
        );
    }

    return $configurazione;
}

try {
    // $argc contiene il numero totale degli argomenti.
    // $argv contiene gli argomenti come array.
    if ($argc === 1) {
        echo "Nessuna opzione specificata. Uso i valori predefiniti.n";
    }

    $configurazione = leggiOpzioni($argv);

    echo "Report configurato correttamente:n";
    echo "Formato: {$configurazione[´formato´]}n";
    echo "Mese: {$configurazione[´mese´]}n";
    echo "Dettagli: " . (
        $configurazione[´dettagli´] ? ´sì´ : ´no´
    ) . "n";
} catch (InvalidArgumentException $errore) {
    fwrite(STDERR, "Errore: {$errore->getMessage()}n");
    fwrite(STDERR, "Usa --help per visualizzare la sintassi.n");

    exit(1);
}

Salva il file come report.php ed eseguilo con:

php report.php --formato=csv --mese=10 --dettagli

Spiegazione

Il ruolo di $argc

$argc è un intero che indica quanti elementi sono presenti nell’array $argv. Se eseguiamo:

php report.php --mese=10

il valore di $argc sarà 2: il primo elemento è il nome dello script e il secondo è l’opzione --mese=10.

Il ruolo di $argv

$argv contiene gli argomenti nell’ordine in cui sono stati digitati. L’elemento $argv[0] normalmente identifica lo script, mentre gli elementi dal secondo in poi rappresentano le opzioni.

Nel codice l’array viene elaborato con array_slice(), così il nome dello script viene escluso. Ogni opzione viene poi analizzata per riconoscere flag senza valore, come --dettagli, oppure opzioni nel formato --nome=valore.

Validazione degli input

Anche se i dati arrivano dal terminale e non da una pagina web, devono essere comunque validati. L’utente potrebbe digitare un formato inesistente, un mese non valido o un’opzione non prevista.

La funzione ctype_digit() verifica che il mese contenga soltanto cifre, mentre in_array() limita i formati ai valori consentiti. In caso di errore viene lanciata un’eccezione e il messaggio viene scritto su STDERR, lo stream standard dedicato agli errori.

Best practice

  • Definisci una sintassi coerente: usa nomi leggibili come --formato=json invece di argomenti numerici difficili da ricordare.
  • Valida sempre i valori: gli argomenti CLI sono input esterni e non devono essere considerati automaticamente sicuri.
  • Fornisci un’opzione --help: aiuta gli utenti a capire come eseguire il comando.
  • Usa codici di uscita significativi: exit(0) indica un’esecuzione corretta, mentre un valore diverso da zero segnala un errore.
  • Separa output normale ed errori: usa echo per i risultati e STDERR per i messaggi di errore.
  • Evita di costruire comandi di shell con input non controllato: se devi usare exec() o funzioni simili, applica una validazione rigorosa e valuta escapeshellarg().
  • Preferisci funzioni dedicate nei comandi complessi: per molte opzioni puoi valutare getopt(), che offre una gestione più strutturata degli argomenti.
  • Indica il tipo restituito: dichiarazioni come declare(strict_types=1) e i type hint rendono il codice più prevedibile.

Riepilogo

$argc e $argv sono superglobali particolarmente utili per sviluppare script PHP da terminale. Il primo indica il numero degli argomenti, mentre il secondo li contiene in un array, incluso il nome dello script alla posizione zero.

Usandoli insieme a validazione, gestione degli errori e codici di uscita, puoi creare comandi affidabili per report, importazioni, esportazioni e attività automatiche. Anche in ambiente CLI è importante trattare gli input come dati non attendibili e progettare una sintassi semplice per chi utilizzerà lo script.

Approfondisci con risorse ufficiali

SHARE