Skip to main content
Wil je aan je package Artisan-commands toevoegen voor diagnose, synchronisatie of installatie, beschouw dan het registreren van het command, het aanmaken van de instantie en het uitvoeren van de verwerking als afzonderlijke stappen. Als je services die alleen tijdens de uitvoering nodig zijn in de constructor resolvet, kan dat zelfs het opstarten van Artisan-commands beïnvloeden die er niets mee te maken hebben. Deze pagina bekijkt de implementatie van Laravel Framework v13.35.0 en gaat dieper in op het registratievoorbeeld met commands() uit Laravel-packages ontwikkelen. Voor de implementatie van het genereren van bestanden zie je GeneratorCommand, en voor deelname aan optimalisatietaken Integratie in optimize.

Expliciet registreren vanuit de provider

Commands in een package registreer je met hun klassenaam in de boot()-methode van de service provider. De automatische detectie van de map app/Console/Commands van de applicatie en de registratie van klassen die een package aanbiedt, zijn twee afzonderlijke ingangen.
Dit voorbeeld gaat ervan uit dat de provider wordt geladen via package discovery of via een expliciete registratie aan de kant van de applicatie. Alleen een command-klasse neerzetten zorgt er niet voor dat de provider van het package automatisch wordt geregistreerd. runningInConsole() bepaalt of je in een console-omgeving zit, niet of een bepaald command wordt uitgevoerd. Wil je ook ondersteunen dat Artisan::call() vanuit een HTTP-request wordt aangeroepen, houd er dan rekening mee dat het command door deze voorwaarde mogelijk niet wordt geregistreerd, en leg het gebruikscontract vast, eventueel met onvoorwaardelijke registratie. Hoe je commands vanuit code uitvoert, lees je in Artisan.

commands() voert het command niet direct uit

ServiceProvider::commands() registreert bij Illuminate\Console\Application::starting() een closure die de ontvangen klassenamen gebruikt. Op dat moment wordt handle() van het command niet aangeroepen. In de gebruikelijke Console Kernel worden de geregistreerde opstartcallbacks later uitgevoerd, wanneer de Artisan Application wordt aangemaakt. Dan geeft resolveCommands() elke klasse door aan resolve() en worden de commands geregistreerd. Het belangrijkste punt is dat het instantiëren van een command niet per se samenvalt met het uitvoeren ervan. Voor gewone klassen die niet de hieronder beschreven speciale route voor uitgestelde registratie volgen, roept resolve() de make() van de container aan, waardoor de constructor en de bijbehorende afhankelijkheden al bij de registratie worden geresolved. Daardoor kan alleen al het uitvoeren van php artisan list of een ander command de constructor van het package-command laten draaien. commands() in boot() plaatsen garandeert op zichzelf niet dat het instantiëren wordt uitgesteld tot de uitvoering.

Afhankelijkheden voor de uitvoering injecteren in handle()

Als voorbeeld maken we een command dat alleen toont of de packageconfiguratie is in- of uitgeschakeld. Net als in de officiële Artisan-documentatie van Laravel 13 definiëren we naam en beschrijving met de attributen Signature en Description.
In dit voorbeeld voegen we geen constructor toe en ontvangen we de configuratie-Repository als argument van handle(). Omdat Command::execute() in het uitvoeringspad van het command de call() van de container gebruikt, worden getypeerde afhankelijkheden geïnjecteerd. Ook een externe API-client of synchronisatieservice kun je op dezelfde plek injecteren als die alleen tijdens de uitvoering nodig is. Heeft het aanmaken van de service zelf of de boot() van een andere provider echter bijwerkingen, dan worden die niet automatisch voorkomen.
Maak in de constructor geen verbinding met externe API’s, werk de database niet bij en overschrijf geen gepubliceerde bestanden. Gebruikers van het package moeten list en help kunnen gebruiken, ook direct na de installatie of als de verbindingsinstellingen nog niet compleet zijn.
Definieer je een eigen constructor, roep dan ook parent::__construct() aan. De parent-constructor van Laravel stelt het command namelijk samen op basis van attributen, signature, description enzovoort.

Signature en uitgestelde registratie zijn aparte mechanismen

De onderzochte Application::resolve() bevat een vertakking die de name van het Symfony-attribuut AsCommand leest en de koppeling tussen naam en klasse in een command map opslaat. In deze vertakking wordt de make() van de container niet direct aangeroepen. De Console Kernel roept later setContainerCommandLoader() aan om een loader in te stellen die deze map gebruikt. Het Laravel-attribuut Signature uit het voorbeeld hierboven staat daarentegen los van deze controle op AsCommand. Alleen Signature toevoegen betekent niet dat de klasse via deze route voor uitgestelde registratie loopt. Beschouw dit verschil als aandachtspunt bij het lezen van de interne implementatie, en beperk eerst de aanmaakkosten en bijwerkingen met de officiële manier om commands te definiëren en met dependency injection in handle(). Ook met een uitgestelde loader kan informatie over het command nodig zijn voor bijvoorbeeld het overzicht of de help, dus ontwerp niet vanuit de aanname dat het command “nooit wordt aangemaakt behalve bij het uitvoeren ervan”.

De registratie van commands niet uitstellen

Het uitgesteld laden van servicebindings en Artisan laten weten dat een command bestaat, zijn twee verschillende dingen. Als een provider DeferrableProvider implementeert, wordt zijn boot() mogelijk pas uitgevoerd wanneer de betreffende service nodig is. Staat de registratie van commands alleen in die boot() en wordt de provider niet geladen voordat Artisan opstart, dan wordt ook de opstartcallback die het bestaan van het command meldt niet geregistreerd. Ook als een service die je naar de dependency injection van handle() hebt verplaatst de uitgestelde provider laadt, lost dat het probleem niet op dat optreedt voordat Artisan het command vindt. Om de beschikbaarheid van commands te garanderen, kun je de registratie in een direct geladen provider plaatsen en alleen de bindings van zware services afsplitsen naar een aparte uitgestelde provider. De precieze vereisten lees je in Uitgestelde service providers.

Waar je op let bij updates

De naam van het command, de argumenten, opties, uitvoer en exitcode vormen een publieke interface die door shellscripts en CI van gebruikers wordt gebruikt. Wijzig ze niet zo licht als de interne implementatie van een klasse, maar controleer de compatibiliteit en de migratieprocedure. Voor de StatusCommand hierboven kun je in een testomgeving die de provider laadt de uitvoer en exitcode als volgt controleren. Voor de testinfrastructuur zie je Laravel-packages testen met Orchestra Testbench, en voor details over assertions Consoletests.
Controleer daarnaast bij commands die zware services gebruiken ook dat de bedrijfsmethoden van de service niet worden aangeroepen wanneer het overzicht of de help wordt uitgevoerd. Alleen controleren dat registratie lukt, brengt de invloed op niet-gerelateerde commands niet aan het licht.

Geraadpleegde primaire bronnen

Laatst gewijzigd op 12 oktober 2026