Skip to content

Command's constructor executed on other commands call #46528

@stebogit

Description

@stebogit
  • Laravel Version: 9.x
  • PHP Version: 8.1
  • Database Driver & Version: Mysql 8

Description:

I created a couple of commands, that are suppose to be available only locally for development, both children of a common a parent class.

abstract class Dumper extends Command
{
    public function __construct()
    {
        parent::__construct();
        dump($this->connection_name);
    }

    public function handle()
    {
        if (!app()->environment('local')) {
           return $this->info('This command is only available for development.');
        }

        // ...
    }
}

class DumperA extends Dumper
{
    protected string $connection_name = 'A';
}

class DumperB extends Dumper
{
    protected string $connection_name = 'B';
}

While developing though I realized that every command class loaded in Laravel is instantiated every time any one of them is run.
In fact even running a completely unrelated command, like config:clear the constructor of both my new commands was executed (note the command does execute successfully anyway):

$ php artisan config:clear
"A" // app/Console/Commands/Dev/Dumper.php:30
"B" // app/Console/Commands/Dev/Dumper.php:30

   INFO  Configuration cache cleared successfully.  

I found this odd as I would expect each command to be completely independent from each other; in fact in the constructor of those dev commands I set some config variables that at this point I suppose would affect other commands.
Am I doing something wrong or missing something? Is using the constructor to set some common attributes not OK for some reason in this case?

This behavior also caused an issue once I pushed to staging, where the commands are also instantiated when the artisan package:discover command is executed (my command looks for a local file that on staging is not available):

Generating optimized autoload files
   > Illuminate\Foundation\ComposerScripts::postAutoloadDump
   > @php artisan package:discover

    [2023-03-17 17:38:29] stack.ERROR: Missing weather.cnf file {"exception":"[object] (Exception(code: 0): Missing weather.cnf file at /tmp/build_f49ece74/app/Console/Commands/Dev/Dumper.php:44)

Now, this might not be considered a bug, however I'd say it is a potentially dangerous unexpected side effect that would be worth clearly documenting, and I'd be happy to send a PR for that.
At the same time, is there maybe a different pattern or method to use to safely set class or instance attributes outside the constructor, or the only/best option is to do so inside the handle method?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions