Как laravel использует $ this context в статических методах? - PullRequest
0 голосов
/ 02 октября 2018

Как Laravel использует метод $ this-> comment () в файле console.php в каталоге "маршрутов", в то время как Artisan :: command () является статическим методом?

enter image description here

<?php

use Illuminate\Foundation\Inspiring;

Artisan::command('inspire', function() {
    $this->comment(Inspiring::(quote));
})->describe('Display an inspiring quote');

Ответы [ 2 ]

0 голосов
/ 02 октября 2018

Laravel очень либерально использует магические методы .Когда вы делаете что-то вроде Artisan::command(), фактическое определение public static function command() отсутствует.Поэтому вместо этого php проверяет, определен ли метод __callStatic(), как ловушка для неопределенных методов.Таким образом, где-то на Artisan Фасаде вы, вероятно, найдете что-то с эффектом:

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.Где-то в файле конфигурации Laravel было сказано, какой корневой класс ассоциируется с этим «Artisan» Facade.Он создает новый экземпляр этого класса и удерживает его, повторно используя его, в течение всего сеанса.

Наконец, чтобы более прямо ответить на ваш вопрос и уточнить ответ Иэнна, это поразило меняВпервые я обнаружил это, но нативный Php фактически поддерживает изменение того, на какой объект $this ссылается ваша анонимная функция.Вы просто вызываете $closure->bindTo($newObject), как если бы Closure был сам по себе, а object и bindTo () - это метод.(Насколько я знаю, под капотом Php на самом деле может не иметь особого значения.)

С этим тоже можно сделать несколько классных вещей.Вы можете настроить свой класс на получение Closure, повторно привязать его к своей области видимости вместо области вызова, сохранить его в статическом ассоциативном массиве и получить к нему доступ позже через.Волшебный __call() метод.В результате получается перегрузка метода ;возможность внедрить пользовательские алгоритмы в вспомогательный класс для последующего использования в декларативном контексте.

Laravel предоставляет инструмент, который может сделать именно это. Макросы , Черта, которую вы можете подключить к чему угодно.И он уже встроен в некоторые наборы инструментов, которые являются известными кандидатами на расширение, такие как Коллекции , Eloquent \ Builder и Ответы .

0 голосов
/ 02 октября 2018

$this не используется внутри самого статического метода, он используется в замыкании, которое передается этому методу. Из руководства Laravel :

Замыкание привязано к базовому экземпляру команды, поэтому у вас есть полный доступ ко всем вспомогательным методам, к которым вы обычно можете получить доступ вполный класс команд.

Так что $this в этом контексте является экземпляром Command.Это достигается с помощью PHP-метода bindTo, который позволяет указать область действия для любого заданного замыкания.


Однако, этот тип методов не является исключительным для команд Artisan.В общем, мы называем эту функцию Facades:

Фасады предоставляют «статический» интерфейс для классов, которые доступны в контейнере приложения .Laravel поставляется с множеством фасадов, которые обеспечивают доступ почти ко всем функциям Laravel.Фасады Laravel служат в качестве «статических прокси» для базовых классов в контейнере службы, обеспечивая преимущество краткого, выразительного синтаксиса, сохраняя при этом большую тестируемость и гибкость, чем традиционные статические методы.

Существует довольно много другихфасады, которые обеспечивают статический доступ к экземплярам, ​​которые находятся внутри сервисного контейнера.Некоторые из наиболее распространенных фасадов и методов:

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