Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

In Symfony 8.1 un comando Console può essere definito in tre modi complementari: come classe invokable con un metodo __invoke(), come singolo metodo pubblico contrassegnato con #[AsCommand], oppure come classe con parametri annotati tramite #[Argument] e #[Option]. Il modello con classe che estende Command resta supportato. Questo articolo spiega cosa cambia, come scrivere ciascuna forma e quale scegliere in un progetto reale.

Tre idee che vengono spesso confuse

Gli attributi PHP al centro di questa novità hanno compiti diversi. Mescolarli è la causa più frequente di codice che sembra corretto ma non viene registrato come previsto.

Elemento Cosa fa Disponibilità documentata
Comando invokable (__invoke()) Il lavoro del comando è nel metodo __invoke(), che restituisce un codice di uscita intero Modello già documentato nella guida Console; la pagina non indica una versione di introduzione diversa dal documento corrente
Comando method-based (#[AsCommand] su metodi pubblici) Ogni metodo pubblico marcato diventa un comando separato, utile per raggruppare operazioni correlate nella stessa classe Introdotto in Symfony 8.1
Attributi #[Argument] e #[Option] Descrivono gli input da terminale sui parametri del metodo Il sistema di risoluzione degli argomenti Console è introdotto in Symfony 8.1

Le tre parti si combinano: un comando invokable può avere parametri annotati, mentre un comando method-based è un caso specifico della stessa famiglia di attributi.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Come scrivere un comando invokable

Una classe invokable non deve estendere Command. L’attributo #[AsCommand] associa il nome del comando e i metadati (descrizione, testo di aiuto ed esempi d’uso), mentre il metodo public function __invoke(): int contiene la logica. Il valore restituito è il codice di uscita:

  • Command::SUCCESS per esecuzione riuscita;
  • Command::FAILURE per errore durante l’esecuzione;
  • Command::INVALID per uso non valido del comando.
use SymfonyComponentConsoleAttributeAsCommand;
use SymfonyComponentConsoleCommandCommand;

#[AsCommand(
    name: 'app:create-user',
    description: 'Creates a new user.',
    help: 'Creates a user account.',
)]
final class CreateUserCommand
{
    public function __invoke(): int
    {
        // Eseguire qui il lavoro del comando.
        return Command::SUCCESS;
    }
}

Per verificare che il comando sia registrato, eseguire php bin/console list e cercare app:create-user. Poi controllare l’aiuto con php bin/console app:create-user --help: deve comparire la descrizione definita nell’attributo.

Quando serve ancora estendere Command

Estendere Command resta la scelta giusta se il comando ha bisogno di hook del ciclo di vita come initialize() o interact(). Una classe invokable può comunque estendere Command, quindi le due forme non sono incompatibili: si può usare un entry point __invoke() e mantenere gli hook della classe base.

Comandi method-based in Symfony 8.1

Il supporto ai comandi definiti su metodi è stato introdotto in Symfony 8.1, come indicato nella documentazione ufficiale sui comandi Console. Con Symfony 8.0 non si devono usare queste forme.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Il caso tipico è raggruppare operazioni utente nella stessa classe. Ogni metodo pubblico ha il proprio #[AsCommand] e può essere eseguito e testato separatamente.

Forma con nomi completi

use SymfonyComponentConsoleAttributeAsCommand;
use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleOutputOutputInterface;

final class UserCommands
{
    #[AsCommand('app:user:create')]
    public function create(OutputInterface $output): int
    {
        return Command::SUCCESS;
    }

    #[AsCommand('app:user:delete')]
    public function delete(OutputInterface $output): int
    {
        return Command::SUCCESS;
    }
}

Forma con prefisso sulla classe

Se la classe porta #[AsCommand('app:user')], i metodi usano nomi relativi come create e delete. Symfony antepone il prefisso di classe agli alias dei metodi, quindi i comandi risultano app:user create e app:user delete.

  • Non scrivere il nome completo nel metodo quando la classe ha già un prefisso: un nome già completo come app:user:create genera un’eccezione, perché i nomi a livello di metodo devono essere relativi.
  • Se la classe ha anche un metodo __invoke(), l’attributo di classe registra un comando con il nome base.
  • Se la classe non ha __invoke(), l’attributo di classe serve soltanto da prefisso e non crea un comando autonomo.

Argomenti e opzioni con gli attributi PHP

Per i comandi invokable, la guida Console consente di dichiarare input direttamente sui parametri con #[Argument] e #[Option]. Symfony determina il valore da passare in base al tipo dichiarato e all’attributo presente sul parametro.

use SymfonyComponentConsoleAttributeArgument;
use SymfonyComponentConsoleAttributeAsCommand;
use SymfonyComponentConsoleAttributeOption;
use SymfonyComponentConsoleCommandCommand;

#[AsCommand(name: 'app:greet')]
final class GreetCommand
{
    public function __invoke(
        #[Argument] string $name,
        #[Option] bool $yell = false,
    ): int {
        // Usare $name e $yell per produrre l'output.
        return Command::SUCCESS;
    }
}

Argomenti e opzioni nella pratica

  • Gli argomenti sono valori posizionali dopo il nome del comando: php bin/console app:greet Maria.
  • Le opzioni non sono posizionali e si scrivono con --: php bin/console app:greet Maria --yell.
  • Il tipo dichiarato conta: non assumere che qualunque parametro venga convertito automaticamente. Verificare per ogni caso il tipo e l’attributo richiesti nella guida agli input Console.

Resolver incorporati

Il sistema di argument value resolver per la Console è introdotto in Symfony 8.1 e include resolver incorporati, tra cui quello per i backed enum. Il post di lancio della versione 8.1 sul blog ufficiale di Symfony presenta la stessa novità in forma sintetica.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

La stessa versione introduce anche il supporto ai file di input nei comandi invokable e l’uso di oggetti come valori predefiniti per argomenti e opzioni. Sono funzioni utili quando il comando cresce, ma non sono necessarie per il caso base.

Registrazione e caricamento del comando

Il comportamento dipende dal contesto in cui il comando viene usato.

Progetto Symfony

Nella configurazione predefinita di un’applicazione Symfony, le classi comando sono individuate grazie a #[AsCommand] e all’autoconfigurazione dei servizi. Se il servizio non viene incluso, il comando non compare nell’elenco. Controllare quindi che la classe rientri nei percorsi dei servizi del progetto.

  1. Verificare che la classe sia caricata dal container, cioè che sia coperta dalla configurazione dei servizi del progetto.
  2. Eseguire php bin/console list e confermare il nome registrato.
  3. Eseguire php bin/console nome:comando --help per controllare descrizione, argomenti e opzioni.

Registrazione manuale o senza attributi

Quando non si usano gli attributi, la documentazione indica il tag console.command per il servizio. Specificare il nome del comando nel tag consente il caricamento lazy anche con registrazione manuale, cioè il comando viene costruito solo quando serve. In un’applicazione Console standalone, senza service container, i metodi possono essere registrati come callable tramite la sintassi PHP first-class callable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Quale forma scegliere

Criterio Classe che estende Command Invokable con __invoke() Metodi con #[AsCommand]
Disponibilità documentata Modello tradizionale, ancora supportato Modello documentato nella guida Console Introdotta in Symfony 8.1
Dove stanno configurazione e input Nei metodi della classe base, tipicamente configure() Sui parametri con #[Argument] e #[Option] Sui parametri dei singoli metodi
Hook initialize() / interact() Disponibili Disponibili se la classe estende Command Non indicato nella documentazione consultata
Più operazioni correlate Una classe per comando Una classe per comando Più comandi nella stessa classe

Per un comando singolo con logica autonoma, la forma invokable è la più diretta. Per un gruppo di operazioni correlate, come creazione, modifica ed eliminazione di un’entità, i metodi con prefisso riducono il numero di classi, a condizione di usare Symfony 8.1 o successivo.

Limiti dell’evidenza

La documentazione ufficiale descrive come si dichiarano i comandi e come vengono risolti gli input, ma non riporta statistiche su prestazioni o adozione di queste funzioni, che quindi non vengono citate qui. Gli esempi di codice seguono la documentazione ufficiale e non sono stati eseguiti in un progetto di produzione; prima di adottarli, verificare la versione installata con composer show symfony/console e confrontare il comportamento con la pagina Symfony Attributes Overview.

Per i dettagli aggiornati, la fonte di riferimento resta la documentazione corrente di Symfony sui comandi Console.

The Bottom Line

Per la maggior parte dei nuovi comandi, la forma invokable con #[AsCommand], #[Argument] e #[Option] è la scelta più leggera. Usare i metodi method-based solo su progetti che hanno Symfony 8.1 e raggruppano davvero più operazioni correlate, e mantenere la classe che estende Command quando servono gli hook del ciclo di vita.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.