laravel 如何在静态方法中使用 $this 上下文?
How laravel use $this context in static methods?
Laravel 如何在 "routes" 目录的 console.php 文件中使用 $this->comment() 方法,而 Artisan::command() 是一个静态方法?
<?php
use Illuminate\Foundation\Inspiring;
Artisan::command('inspire', function() {
$this->comment(Inspiring::(quote));
})->describe('Display an inspiring quote');
$this
没有在静态方法本身内部使用,它在传递给该方法的闭包中使用。 From the Laravel manual:
The Closure is bound to the underlying command instance, so you have full access to all of the helper methods you would typically be able to access on a full command class.
所以 $this
在这个上下文中是一个 Command 实例。这是使用 PHP 的 bindTo
方法实现的,该方法允许您指定任何给定闭包的范围。
虽然这种方法并不是 Artisan 命令独有的。一般来说,我们称这个特征为Facades
:
Facades provide a "static" interface to classes that are available in the application's service container. Laravel ships with many facades which provide access to almost all of Laravel's features. Laravel facades serve as "static proxies" to underlying classes in the service container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods.
还有很多其他外观,它们都提供对服务容器内实例的静态访问。一些更常见的外观和方法是:
Cache::get('key')
和 Cache::set('key', 'value')
Request::input('some_field')
和 Request::only('some_field')
Log::info('be aware of this...')
- ...
Laravel 非常自由地使用 magic methods。当您执行 Artisan::command()
之类的操作时,实际上并没有 public static function command()
定义。所以 php 而是查看是否定义了 __callStatic()
方法,作为未定义方法的总称。因此,在 Artisan
Facade 的某处,您可能会找到具有以下效果的内容:
public static function __callStatic($name, array $args = [])
{
$newObj = new static();
if (method_exists($newObj, $name)) {
return $newObj->$name(...$args);
}
}
另一个棘手的事情是,你得到的对象很可能不是像上面的例子那样新实例化的。其中大部分都遵循 Singleton Pattern,这意味着您不仅静态调用非静态方法,而且每次都针对目标对象的 相同 实例调用它.
$newObj = new static();
看起来更像
self::$preexistingObject = self::$preexistingObject ?: new static();
$newObj = self::$preexistingObject;
大多数这种魔法发生在 ServiceProviders 'boot' 启动时。在配置文件的某处,Laravel 被告知哪个根 class 与那个 "Artisan" 门面相关联。它会创建该 class 的一个新实例,并在该会话期间保留并重复使用它。
最后,为了更直接地回答你的问题并详细说明 Iainn 的回答,这让我第一次发现它时大吃一惊,但原生 Php 实际上支持更改 $this
实际引用的对象在你的匿名函数中。您只需调用 $closure->bindTo($newObject)
,就好像闭包本身就是对象,而 bindTo() 是一个方法。 (据我所知,在幕后,Php 可能实际上并没有太大区别。)
你也可以用它做一些很酷的事情。您可以将 class 设置为接收闭包,将其重新绑定到它自己的范围而不是调用者的范围,将其保留在静态关联数组中,稍后通过访问它。魔术 __call()
方法。结果基本上是 method-overloading; an opportunity to inject custom algorithms into a helper-class for use later in a declarative context.
Laravel 提供了可以做到这一点的工具。 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.
Laravel 如何在 "routes" 目录的 console.php 文件中使用 $this->comment() 方法,而 Artisan::command() 是一个静态方法?
<?php
use Illuminate\Foundation\Inspiring;
Artisan::command('inspire', function() {
$this->comment(Inspiring::(quote));
})->describe('Display an inspiring quote');
$this
没有在静态方法本身内部使用,它在传递给该方法的闭包中使用。 From the Laravel manual:
The Closure is bound to the underlying command instance, so you have full access to all of the helper methods you would typically be able to access on a full command class.
所以 $this
在这个上下文中是一个 Command 实例。这是使用 PHP 的 bindTo
方法实现的,该方法允许您指定任何给定闭包的范围。
虽然这种方法并不是 Artisan 命令独有的。一般来说,我们称这个特征为Facades
:
Facades provide a "static" interface to classes that are available in the application's service container. Laravel ships with many facades which provide access to almost all of Laravel's features. Laravel facades serve as "static proxies" to underlying classes in the service container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods.
还有很多其他外观,它们都提供对服务容器内实例的静态访问。一些更常见的外观和方法是:
Cache::get('key')
和Cache::set('key', 'value')
Request::input('some_field')
和Request::only('some_field')
Log::info('be aware of this...')
- ...
Laravel 非常自由地使用 magic methods。当您执行 Artisan::command()
之类的操作时,实际上并没有 public static function command()
定义。所以 php 而是查看是否定义了 __callStatic()
方法,作为未定义方法的总称。因此,在 Artisan
Facade 的某处,您可能会找到具有以下效果的内容:
public static function __callStatic($name, array $args = [])
{
$newObj = new static();
if (method_exists($newObj, $name)) {
return $newObj->$name(...$args);
}
}
另一个棘手的事情是,你得到的对象很可能不是像上面的例子那样新实例化的。其中大部分都遵循 Singleton Pattern,这意味着您不仅静态调用非静态方法,而且每次都针对目标对象的 相同 实例调用它.
$newObj = new static();
看起来更像
self::$preexistingObject = self::$preexistingObject ?: new static();
$newObj = self::$preexistingObject;
大多数这种魔法发生在 ServiceProviders 'boot' 启动时。在配置文件的某处,Laravel 被告知哪个根 class 与那个 "Artisan" 门面相关联。它会创建该 class 的一个新实例,并在该会话期间保留并重复使用它。
最后,为了更直接地回答你的问题并详细说明 Iainn 的回答,这让我第一次发现它时大吃一惊,但原生 Php 实际上支持更改 $this
实际引用的对象在你的匿名函数中。您只需调用 $closure->bindTo($newObject)
,就好像闭包本身就是对象,而 bindTo() 是一个方法。 (据我所知,在幕后,Php 可能实际上并没有太大区别。)
你也可以用它做一些很酷的事情。您可以将 class 设置为接收闭包,将其重新绑定到它自己的范围而不是调用者的范围,将其保留在静态关联数组中,稍后通过访问它。魔术 __call()
方法。结果基本上是 method-overloading; an opportunity to inject custom algorithms into a helper-class for use later in a declarative context.
Laravel 提供了可以做到这一点的工具。 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.