Интересная фича, возможность использовать Фасады (Facades) на лету, появилась в Laravel 5.4. Я не буду объяснять, что такое Фасады — все подробно описано в официальной документации. Предполагается, что вы с ними знакомы.
Как создать свой Фасад
В качестве примера я позаимствую класс, используемый Taylor Otwell:
namespace App; class Zonda { public function zurf() { return 'Zurfing'; } }
Учитывая этот класс, мы должны определить собственный Фасад следующим образом:
namespace App\Facades; use Illuminate\Support\Facades\Facade; class FacadeName extends Facade { protected static function getFacadeAccessor() { return App\Zonda::class; } }
Последний шаг — регистрируем Фасад в config/app.php:
'aliases' => [ // ... 'Zonda' => App\Facades\FacadeName::class ]
Идея автоматических фасадов заключается в автоматизации этого потока для определения встроенных фасадов:
use Facades\{ App\Zonda }; Route::get('/', function () { return Zonda::zurf(); });
Используя общее пространство имен Facades\.
За кулисами
Каждый раз, когда мы используем групповой импорт, который начинается с пространства имен Facades, новый фасад создается на лету. Это также работает и с однострочным импортом.
Это поведение обрабатывает Illuminate\Foundation\AliasLoader. Он регистрирует пользовательскую функцию автозагрузки при старте фреймворка.
/** * Register the loader on the auto-loader stack. * * @return void */ public function register() { if (! $this->registered) { $this->prependToLoaderStack(); $this->registered = true; } } /** * Prepend the load method to the auto-loader stack. * * @return void */ protected function prependToLoaderStack() { spl_autoload_register([$this, 'load'], true, true); }
Когда фреймворк загружается, он вызывает метод register и добавляет в стек загрузчика метод load.
/** * Load a class alias if it is registered. * * @param string $alias * @return bool|null */ public function load($alias) { if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) { $this->loadFacade($alias); return true; } if (isset($this->aliases[$alias])) { return class_alias($this->aliases[$alias], $alias); } }
Если $alias начинается с $facadeNamespace (по умолчанию это Facade), то он загружает пользовательский фасад на лету, используя метод loadFacade.
/** * Load a real-time facade for the given alias. * * @param string $alias * @return bool */ protected function loadFacade($alias) { tap($this->ensureFacadeExists($alias), function ($path) { require $path; }); }
После того, как Фасад гарантировано существует, ему требуются сгенерированные в реальном времени фасады в пространстве имен.
Метод sureFacadeExists делает волшебство реальным.
/** * Ensure that the given alias has an existing real-time facade class. * * @param string $class * @return string */ protected function ensureFacadeExists($alias) { if (file_exists($path = base_path('bootstrap/cache/facade-'.sha1($alias).'.php'))) { return $path; } file_put_contents($path, $this->formatFacadeStub( $alias, file_get_contents(__DIR__.'/stubs/facade.stub') )); return $path; }
Первым делом проверяется, существует ли уже Фасад. Как вы видите, кэшированные фасады генерируются с использованием хеш-функции sha1 на псевдониме. Если фасад кэширован, то он возвращает путь к файлу.
В противном случае Фасад генерирует на лету, используя эту заглушку.
namespace DummyNamespace; use Illuminate\Support\Facades\Facade; /** * @see \DummyTarget */ class DummyClass extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'DummyTarget'; } }
Как вы видите, это похоже на то, что мы использовали раньше, создавая его вручную. Я показал вам, что именно делает formatFacadeStub.
Остальная часть метода load работает также, как и раньше, поэтому остальное можете посмотреть сами :D
Предлагаю начать использовать автоматические фасады, когда это возможно, их влияние на производительность незначительно.
О том, когда обычно используются фасады, вы можете прочесть в официальной документации.
Автор: Nicola Malizia
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.