How does Laravel uses $this->comment() method inside console.php file in "routes" directory while Artisan::command() being a static method?
<?php
use Illuminate\Foundation\Inspiring;
Artisan::command('inspire', function() {
$this->comment(Inspiring::(quote));
})->describe('Display an inspiring quote');
Laravel makes very liberal use of magic methods. When you do something like
Artisan::command()
, there is no actualpublic static function command()
definition. So php instead looks to see if a__callStatic()
method is defined, as a catchall for undefined methods. So somewhere in theArtisan
Facade, you're likely to find something to the effect of:Another tricky thing here is, more than likely the object you get back is not freshly instantiated as in the above example. Most of these follow the Singleton Pattern, meaning not only are you calling a non-static method statically, but you're calling it against the same instance of the target object every time.
Would look more like
Most of this magic happens when the ServiceProviders 'boot' up. Somewhere in a configuration file, Laravel has been told what root class to associate with that "Artisan" Facade. It creates a new instance of that class, and holds on to it, reusing it, for the duration of that session.
Finally, to more directly answer your question and elaborate on Iainn's answer, this blew my mind the first time I discovered it, but native Php actually supports changing which object
$this
actually refers to within your anonymous function. You just call$closure->bindTo($newObject)
, as if the Closure is itself and object and bindTo() is a method. (For all I know, under the hood, Php might not actually make much of a distinction.)You can do some cool stuff with this too. You could set your class up to receive a Closure, re-bind it to its own scope instead of that of the caller, retain it in a static associative-array, and access it later via. the Magic
__call()
method. The result is basically method-overloading; an opportunity to inject custom algorithms into a helper-class for use later in a declarative context.Laravel provides a tool that can do just that. Macros, a Trait that you can plug into whatever you like. And it already has it baked into some toolsets that are known candidates for expansion, such as Collections, Eloquent\Builder, and Responses.
$this
isn't being used inside the static method itself, it's used in the closure that's passed to that method. From the Laravel manual:So
$this
in this context is a Command instance. This is achieved using PHP'sbindTo
method, which allows you to specify the scope for any given closure.This kind of methods are not exclusive to Artisan commands though. In general, we call this feature
Facades
:There are quite some other facades, which all provide static access to instances that live within the service container. Some of the more common facades and methods are:
Cache::get('key')
andCache::set('key', 'value')
Request::input('some_field')
andRequest::only('some_field')
Log::info('be aware of this...')