Improving Artisan commands original

by Freek Van der Herten – 3 minute read

In this small blog post, I'd like to give you a couple of tips to make your Artisan commands better.

Use the fully qualified class name to schedule commands

You probably know that you can schedule artisan commands in the console kernel like this.

// app/Console/Kernel.php

class Kernel extends ConsoleKernel
{
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('email-campaigns:send-scheduled-campaigns')->everyMinute();
    }
}

Did you know that you could use the fully qualified name of a command too?

class Kernel extends ConsoleKernel
{
    protected function schedule(Schedule $schedule)
    {
        $schedule->command(SendScheduledEmailCampaigns::class)->everyMinute();
    }
}

Using the fully qualified class name has some nice benefits. Any decent IDE will allow you to click through a command. Also, when performing a name refactor on the command, decent IDEs will automatically change the name of the command everywhere, including in the kernel.

Make commands smaller

When you scaffold a command using make:command, the produced code is quite verbose. Here's an example:

class SendScheduledEmailCampaigns extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'email-campaigns:send-scheduled-campaigns';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }
    
    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        // do the work
    }
}

I like to make those commands as small as possible by removing any cruft that doesn't make the code clearer. Those comments are not necessary. Also, the $description is not mandatory, so you can lose that if the command name is already clear enough.

class SendScheduledEmailCampaigns extends Command
{
    protected $signature = 'email-campaigns:send-scheduled-campaigns';
    
    public function handle()
    {
        // do the work
    }
}

To me, this is more readable. We didn't lose any information by removing all those lines.

Use the handle method to inject dependencies

I sometimes see the constructor is used to inject dependencies.

class SendScheduledEmailCampaigns extends Command
{
    protected $signature = 'email-campaigns:send-scheduled-campaigns';
    
    /** @var MyDependency **/
    protected $myDependency;
    
    public function __construct(MyDependency $myDependency) 
    {
       $this->myDependency = $myDependency;
    }
    
    public function handle()
    {
        // do something with `$this->myDependency`
    }
}

This approach is not ideal. It was recently brought to my attention that the constructor of each registered command will get executed when artisan is invoked.

To inject dependencies is much better to use the handle method. Everything you specify there will be resolved out of the IoC container when your command executes.

class SendScheduledEmailCampaigns extends Command
{
    protected $signature = 'email-campaigns:send-scheduled-campaigns';
        
    public function handle(MyDependency $myDependency)
    {
        // do something with `$myDependency`
    }
}

Join 9,500+ smart developers

Get my monthly newsletter with what I learn from running Spatie, building Oh Dear, and maintaining 300+ open source packages. Practical takes on Laravel, PHP, and AI that you can actually use.

"Always fresh, useful tips and articles. Carefully selected community content. My favorite newsletter, which I look forward to every time."

Bert De Swaef — Developer at Vulpo & Youtuber at Code with Burt

No spam. Unsubscribe anytime. You can also follow me on X.

Found something interesting to share? Submit a link to the community section.