Skip to main content
Wenn Sie Ihrem Paket Artisan-Befehle für Diagnose, Synchronisierung oder Installation hinzufügen möchten, betrachten Sie die Registrierung des Befehls, die Erzeugung der Instanz und die Ausführung der Verarbeitung getrennt voneinander. Wenn Sie Services, die nur zur Laufzeit benötigt werden, im Konstruktor auflösen, kann das sogar den Start unbeteiligter Artisan-Befehle beeinträchtigen. Diese Seite untersucht die Implementierung in Laravel Framework v13.35.0 und vertieft das Registrierungsbeispiel mit commands() aus Grundlagen der Paketentwicklung. Zur Implementierung der Dateigenerierung siehe GeneratorCommand, zur Teilnahme an Optimierungsaufgaben siehe Integration in optimize.

Befehle explizit im Provider registrieren

Befehle in einem Paket werden in der Methode boot() des Service Providers über ihren Klassennamen registriert. Die automatische Erkennung von app/Console/Commands der Anwendung und die Registrierung von Klassen, die ein Paket bereitstellt, sind getrennte Einstiegspunkte.
Dieses Beispiel setzt voraus, dass der Provider über die Paketerkennung oder durch explizite Registrierung in der Anwendung geladen wird. Allein durch das Ablegen einer Befehlsklasse wird der Provider des Pakets nicht automatisch registriert. runningInConsole() prüft, ob die Anwendung in einer Konsolenumgebung läuft, nicht ob ein bestimmter Befehl ausgeführt wird. Wenn Sie auch den Aufruf über Artisan::call() innerhalb von HTTP-Requests unterstützen, berücksichtigen Sie, dass diese Bedingung die Registrierung verhindern kann, und legen Sie den Nutzungsvertrag fest, einschließlich einer möglichen bedingungslosen Registrierung. Wie Sie Befehle programmgesteuert ausführen, erfahren Sie unter Artisan.

commands() führt den Befehl nicht sofort aus

ServiceProvider::commands() registriert bei Illuminate\Console\Application::starting() eine Closure, die die übergebenen Klassennamen verwendet. Zu diesem Zeitpunkt wird handle() des Befehls nicht aufgerufen. Beim regulären Console Kernel werden die registrierten Start-Callbacks später ausgeführt, wenn die Artisan Application erzeugt wird. Dort übergibt resolveCommands() jede Klasse an resolve() und setzt die Registrierung der Befehle fort. Entscheidend ist hier: Die Instanz eines Befehls wird nicht unbedingt zum selben Zeitpunkt erzeugt, zu dem der Befehl ausgeführt wird. Bei regulären Klassen, die nicht den später beschriebenen speziellen Pfad für verzögerte Registrierung nutzen, ruft resolve() das make() des Containers auf, sodass der Konstruktor und seine Abhängigkeiten bereits bei der Registrierung aufgelöst werden. Daher kann der Konstruktor eines Paketbefehls auch dann laufen, wenn Sie nur php artisan list oder einen anderen Befehl ausführen. Dass commands() in boot() steht, garantiert für sich genommen nicht, dass die Instanziierung bis zur Ausführung verzögert wird.

Laufzeitabhängigkeiten in handle() injizieren

Als Beispiel erstellen wir einen Befehl, der nur anzeigt, ob die Paketkonfiguration aktiviert oder deaktiviert ist. Wie in der offiziellen Artisan-Dokumentation von Laravel 13 werden Name und Beschreibung mit den Attributen Signature und Description definiert.
Dieses Beispiel fügt keinen Konstruktor hinzu, sondern erhält das Konfigurations-Repository als Argument von handle(). Da Command::execute() im Ausführungspfad des Befehls das call() des Containers verwendet, werden typisierte Abhängigkeiten injiziert. Auch externe API-Clients oder Synchronisierungsservices können Sie an derselben Stelle injizieren, wenn sie nur zur Laufzeit benötigt werden. Hat jedoch die Erzeugung des Services selbst oder das boot() eines anderen Providers Seiteneffekte, werden diese dadurch nicht automatisch verhindert.
Stellen Sie im Konstruktor keine Verbindungen zu externen APIs her, aktualisieren Sie keine Datenbank und überschreiben Sie keine veröffentlichten Dateien. Nutzer Ihres Pakets müssen list und help direkt nach der Installation verwenden können, auch wenn die Verbindungseinstellungen noch nicht vollständig sind.
Wenn Sie einen eigenen Konstruktor definieren, rufen Sie auch parent::__construct() auf. Der übergeordnete Konstruktor von Laravel konfiguriert den Befehl anhand von Attributen, Signature, Description und Ähnlichem.

Signature und verzögerte Registrierung sind getrennte Mechanismen

Das untersuchte Application::resolve() enthält einen Zweig, der den name des Symfony-Attributs AsCommand liest und die Zuordnung von Name und Klasse in einer Command Map speichert. In diesem Zweig wird das make() des Containers nicht sofort aufgerufen. Der Console Kernel ruft später setContainerCommandLoader() auf und richtet einen Loader ein, der diese Map verwendet. Das im obigen Beispiel verwendete Laravel-Attribut Signature ist dagegen unabhängig von dieser AsCommand-Prüfung. Allein durch das Hinzufügen von Signature gelangt eine Klasse nicht auf diesen Pfad der verzögerten Registrierung. Behandeln Sie diesen Unterschied als Hinweis beim Lesen der internen Implementierung und halten Sie Erzeugungskosten und Seiteneffekte zunächst mit der offiziellen Befehlsdefinition und der Abhängigkeitsinjektion in handle() gering. Auch wenn ein verzögerter Loader vorhanden ist, können Befehlsinformationen etwa für Auflistungen oder die Hilfe benötigt werden. Gehen Sie beim Design daher nicht davon aus, dass „der Befehl ausschließlich dann erzeugt wird, wenn er ausgewählt und ausgeführt wird“.

Die Registrierung von Befehlen nicht verzögern

Das verzögerte Laden von Service-Bindings und das Bekanntmachen eines Befehls bei Artisan sind zwei verschiedene Dinge. Wenn ein Provider DeferrableProvider implementiert, wird sein boot() unter Umständen gar nicht ausgeführt, bis der betreffende Service benötigt wird. Wenn Sie nur die Befehlsregistrierung in dieses boot() legen und der Provider bis zum Start von Artisan nicht geladen wird, wird auch der Start-Callback, der den Befehl bekannt macht, nicht registriert. Selbst wenn ein in die Abhängigkeitsinjektion von handle() verlagerter Service den deferred Provider laden würde, löst das nicht das Problem, das auftritt, bevor Artisan den Befehl findet. Damit Befehle zuverlässig verfügbar sind, können Sie die Registrierung in einem sofort geladenen Provider unterbringen und nur die schwergewichtigen Service-Bindings in einen separaten deferred Provider auslagern. Die konkreten Anforderungen finden Sie unter Deferred Service Provider.

Was bei Updates zu prüfen ist

Befehlsnamen, Argumente, Optionen, Ausgaben und Exit-Codes sind öffentliche Schnittstellen, die von Shell-Skripten und CI Ihrer Nutzer verwendet werden. Ändern Sie sie nicht so unbekümmert wie klasseninterne Details, sondern prüfen Sie Kompatibilität und Migrationsschritte. Für den obigen StatusCommand können Sie Ausgabe und Exit-Code in einer Testumgebung, in der der Provider geladen ist, wie folgt überprüfen. Zur Testinfrastruktur siehe Pakete testen, Details zu Assertions finden Sie unter Console Tests.
Prüfen Sie darüber hinaus bei Befehlen, die schwergewichtige Services verwenden, dass die Geschäftsmethoden des Services beim Ausführen von Auflistung oder Hilfe nicht aufgerufen werden. Wenn Sie nur prüfen, ob sich ein Befehl registrieren lässt, erkennen Sie keine Auswirkungen auf unbeteiligte Befehle.

Herangezogene Primärquellen

Zuletzt geändert am 12. Oktober 2026