My team at Spatie is currenlty building Mailcoach, a solution to self host your e-mail newsletter. Mailcoach can be used a stand alone software or as a Laravel package. Subscribe now at Mailcoach to get a notification as soon as we release it.

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`
    }
}

Stay up to date with all things Laravel, PHP, and JavaScript.

Follow me on Twitter. I regularly tweet out programming tips, and what I myself have learned in ongoing projects.

Every two weeks I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Comments

You can comment on this post by replying to this tweet.
Mike liked on 12th November 2019
Sendoa Portuondo liked on 10th November 2019
Rob Allport 🇬🇧 liked on 10th November 2019
DN liked on 10th November 2019
Tom Witkowski liked on 10th November 2019
Sowren Sen liked on 10th November 2019
Morley L Abuyabor Jr liked on 10th November 2019
Andrew Broberg liked on 10th November 2019
Jesse Kramer retweeted on 10th November 2019
ali ali liked on 10th November 2019
Kristoffer Högberg liked on 10th November 2019
Mattias Geniar liked on 10th November 2019
Cristian liked on 10th November 2019
LaravelLive Punjab retweeted on 10th November 2019
Manojkiran liked on 10th November 2019
Tom Schlick liked on 10th November 2019
Spatie retweeted on 10th November 2019
LaravelLive Punjab liked on 10th November 2019
Jimmy Lipham liked on 10th November 2019