laravel如何在静态方法中使用$ this这个上下文?

Abh*_*ash 5 php oop static-methods laravel laravel-5

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');
Run Code Online (Sandbox Code Playgroud)

iai*_*inn 11

$this在静态方法本身中没有使用它,它在传递给该方法的闭包中使用.从Laravel手册:

Closure绑定到底层命令实例,因此您可以完全访问通常能够在完整命令类上访问的所有辅助方法.

所以$this在这个上下文中是一个Command实例.这是使用PHP的bindTo方法实现的,它允许您指定任何给定闭包的范围.


但这种方法并不仅限于Artisan命令.一般来说,我们称之为此功能Facades:

Facade为应用程序服务容器中可用的类提供"静态"接口.Laravel拥有许多外墙,可以使用几乎所有Laravel的功能.Laravel外观充当服务容器中底层类的"静态代理",提供简洁,富有表现力的语法,同时保持比传统静态方法更多的可测试性和灵活性.

还有一些其他外观,它们都提供对服务容器内的实例的静态访问.一些更常见的外观和方法是:

  • Cache::get('key')Cache::set('key', 'value')
  • Request::input('some_field')Request::only('some_field')
  • Log::info('be aware of this...')
  • ...


Cla*_*ore 5

Laravel 非常自由地使用魔法方法。当你做类似的事情时Artisan::command(),没有实际的public static function command()定义。所以 php 而是查看是否__callStatic()定义了一个方法,作为未定义方法的总括。因此,在ArtisanFacade 的某个地方,您可能会发现以下效果:

public static function __callStatic($name, array $args = [])
{
    $newObj = new static();
    if (method_exists($newObj, $name)) {
        return $newObj->$name(...$args);
    }
}
Run Code Online (Sandbox Code Playgroud)

另一个棘手的事情是,您返回的对象很可能没有像上面的示例那样刚刚实例化。其中大部分都遵循Singleton Pattern,这意味着您不仅静态地调用非静态方法,而且每次都针对目标对象的同一实例调用它。

$newObj = new static();
Run Code Online (Sandbox Code Playgroud)

看起来更像

self::$preexistingObject = self::$preexistingObject ?: new static();
$newObj = self::$preexistingObject;
Run Code Online (Sandbox Code Playgroud)

大多数这种魔法发生在 ServiceProviders“启动”时。在配置文件的某个地方,Laravel 被告知要与“Artisan”Facade 关联的根类。它创建该类的一个新实例,并在该会话期间保留它并重用它。

最后,为了更直接地回答您的问题并详细说明 Iainn 的回答,我第一次发现它时让我大吃一惊,但本机 Php 实际上支持更改$this匿名函数中实际引用的对象。您只需调用$closure->bindTo($newObject),就好像闭包本身就是对象,而 bindTo() 是一个方法。(据我所知,在幕后,Php 可能实际上并没有太大区别。)

你也可以用它做一些很酷的事情。你可以设置你的类来接收一个闭包,将它重新绑定到它自己的范围而不是调用者的范围,将它保留在一个静态关联数组中,然后通过它访问它。魔术__call()方法。结果基本上是方法重载;有机会将自定义算法注入助手类,以便稍后在声明性上下文中使用。

Laravel 提供了一个工具可以做到这一点。 Macros,你可以插入任何你喜欢的特性。它已经将它融入到一些已知的扩展候选工具集中,例如CollectionsEloquent\BuilderResponses