Heim  >  Artikel  >  Backend-Entwicklung  >  Analyse des Fassaden-Erscheinungsbildsystems von Laravel

Analyse des Fassaden-Erscheinungsbildsystems von Laravel

不言
不言Original
2018-07-06 17:13:261482Durchsuche

Dieser Artikel stellt hauptsächlich die Analyse des Fassaden-Erscheinungsbildsystems vor. Er hat einen gewissen Referenzwert. Jetzt können Freunde in Not darauf zurückgreifen.

Heute werden wir etwas über die Kernarchitektur von Laravel erfahren. Ein weiteres Thema „Fassade“.

Dieser Artikel beginnt mit den folgenden Aspekten, um das Funktionsprinzip von Facade in Laravel umfassend zu erläutern, um das Verständnis aller nachfolgenden Facade zu erleichtern übersetzt als „Aussehen“:

  • Eine kurze Einführung in das Designmuster „Aussehen“

  • Das Ladeprinzip von Laravels „Aussehen“;

  • Grundlegende Verwendung von Laravel „Aussehen“.

Was ist das Designmuster „Darstellung“?

Darstellungsmusterdefinition

Bietet einen einheitlichen Zugang für eine Reihe von Schnittstellen in einem Subsystem. Das Fassadenmuster definiert eine High-Level-Schnittstelle, die die Verwendung dieses Subsystems erleichtert.

Das Erscheinungsmuster ist ein sehr häufig verwendetes strukturelles Entwurfsmuster. Es vereinfacht die Interaktion zwischen dem Client und dem Subsystem, indem es eine Erscheinungsrolle einführt.
Bietet einen komplexen Subsystemaufruf. Der einheitliche Eingang reduziert die Kopplung zwischen dem Subsystem und Client, und der Client-Aufruf ist sehr praktisch. - Design Pattern Java Edition

Kern besteht darin, eine Verbindung zwischen dem Client (Benutzer) und dem Subsystem (Schnittstelle oder Dienst) einzuführen. Aussehen“-Charakter.

Transformieren Sie die direkte Kopplung zwischen Benutzern und Subsystemen in eine einheitliche Schnittstelle, die von der „Appearance“-Klasse für Benutzer bereitgestellt wird, um die Kopplung zwischen dem Client und dem Subsystem zu reduzieren.

Strukturdiagramm:

Analyse des Fassaden-Erscheinungsbildsystems von Laravel

Über „Darstellungsmodus“ können Sie Design Pattern Java Edition – Darstellungsmodus

Laravel Appearance Component

Die „Erscheinungsbild“-Komponente in Laravel ist eigentlich ein „statischer Proxy“ der zugrunde liegenden Klasse im Service-Container. Sie verwendet die im Laravel-Kern definierten „Verträge“ (in Laravel auch

Dienste genannt). oder das, was wir normalerweise „Schnittstelle“ nennen), das auf statische und aufrufbare Weise in jeden „Erscheinungsbild“-Dienst eingekapselt ist, damit wir es verwenden können.

Prinzip des Ladens des Erscheinungsbilds

Bevor wir erklären, wie Erscheinungsbildkomponenten verwendet werden, analysieren wir zunächst eingehend, wie die Komponente „Erscheinungsbild“ von Laravel in das Projekt geladen wird. Dieser Schritt ist

die Voraussetzung, um die Komponente „Aussehen“ sinnvoll nutzen zu können.

Konfiguration der Darstellungskomponenten

Die Konfigurationsdaten aller integrierten Darstellungskomponenten werden wie bei anderen Laravel-Diensten in der Datei

config/app.php definiert. Werfen wir einen Blick auf die Konfigurationsdaten des Knotens aliases:

    ...
    'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        ...
    ],
    ...

Das Definitionsformat für die Erscheinungskonfiguration folgt dem Datenformat von

"alias":"appearance class" . Wenn eine HTTP-Anfrage empfangen wird, werden diese „Look-and-Feel“-Komponenten während der Anforderungsverarbeitungsphase in den Dienst geladen.

Als nächstes führen wir eine eingehende Analyse des Ladevorgangs des Auftrittsdienstes durch.

Laden des Appearance-Dienstes

Das Laden des „Appearance“-Dienstes wird durch das

IlluminateFoundationBootstrapRegisterFacades::class Startprogramm abgeschlossen, das im IlluminateFoundationHttpKernel definiert ist Kernel.

Bootstrap startet den Erscheinungsdienst

Wenn Sie meinen anderen Artikel über die ausführliche Analyse der Implementierungsprinzipien von Laravel-Dienstanbietern gelesen haben, sollten Sie mit dem Bootstrap nicht allzu unbekannt sein.

Der Bootstrap schließt den Boot-Start

bootstrap() nach der Verarbeitung der HTTP-Anfrage ab. Hier müssen wir also tief in die Klasse RegisterFacades eintauchen, um eine detailliertere Verarbeitung zu verstehen.

<?php

namespace Illuminate\Foundation\Bootstrap;

use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\Facades\Facade;
use Illuminate\Foundation\PackageManifest;
use Illuminate\Contracts\Foundation\Application;

/**
 * @link https://github.com/laravel/framework/blob/56a58e0fa3d845bb992d7c64ac9bb6d0c24b745a/src/Illuminate/Foundation/Bootstrap/RegisterFacades.php
 */
class RegisterFacades
{
    /**
     * Bootstrap the given application. 引导启动服务
     */
    public function bootstrap(Application $app)
    {
        // 清除已解析的「外观」服务实例
        Facade::clearResolvedInstances();

        // 将 Laravel 服务容器注入到「外观」服务
        Facade::setFacadeApplication($app);

        // 加载所有外观服务
        AliasLoader::getInstance(array_merge(
            $app->make(&#39;config&#39;)->get(&#39;app.aliases&#39;, []),
            $app->make(PackageManifest::class)->aliases()
        ))->register();
    }
}

Das Laden des Darstellungsdienstes hat die

AliasLoader-Komponentenvervollständigung:

  • Zunächst erfolgt dies aus der Konfigurationsdatei

    config/app .php Alle „Erscheinungsbild“-Dienstkonfigurationen in aliases lesen;

  • und dann den Alias-Dienst aus der Manifestdatei

    $app-> lesen ;make(PackageManifest ::class)->aliases();

  • Füge die beiden Konfigurationsarrays zusammen und injiziere sie in

    AliasLoader Abgeschlossen Registrierung (Registrierung) .

Darstellungsdienst registrieren

Schließlich werfen wir einen Blick darauf, wie der

AliasLoader-Loader alle „Darstellungs“-Dienste in das System lädt.

<?php

namespace Illuminate\Foundation;

/**
 * @link https://github.com/laravel/framework/blob/56a58e0fa3d845bb992d7c64ac9bb6d0c24b745a/src/Illuminate/Foundation/AliasLoader.php
 */
class AliasLoader
{
    /**
     * Get or create the singleton alias loader instance. 获取或创建「别名加载器」单例实例。
     */
    public static function getInstance(array $aliases = [])
    {
        if (is_null(static::$instance)) {
            return static::$instance = new static($aliases);
        }

        $aliases = array_merge(static::$instance->getAliases(), $aliases);

        static::$instance->setAliases($aliases);

        return static::$instance;
    }

    /**
     * Set the registered aliases. 设置需注册别名数据。
     */
    public function setAliases(array $aliases)
    {
        $this->aliases = $aliases;
    }

    /**
     * Register the loader on the auto-loader stack. 将加载器注册到自动加载中。
     */
    public function register()
    {
        if (! $this->registered) {
            $this->prependToLoaderStack();

            $this->registered = true;
        }
    }

    /**
     * Prepend the load method to the auto-loader stack. 设置自动加载方法。
     */
    protected function prependToLoaderStack()
    {
        // 将 AliasLoader 的 load 方法作为 __autoload 的实现
        spl_autoload_register([$this, &#39;load&#39;], true, true);
    }

    /**
     * Load a class alias if it is registered.从注册过的服务中加载这个「外观」服务。
     */
    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);
        }
    }
}

Hinweis Hier sind die Wissenspunkte In AliasLoader->register() beinhaltet das Abschließen der „Foreign Service Registration“ die Anwendung von zwei PHP-Kenntnissen:

  • Verwendung der in PHP integrierten magischen Methode

    __autoload;

  • So erstellen Sie Aliase für Klassen in PHP.

➤ 1. Dynamische Einführung des Erscheinungsdienstes

Wir wissen, dass die Funktion der magischen Methode

__autoload darin besteht, zu versuchen, undefinierte Klassen zu laden Wenn wir eine nicht eingeführte Klasse verwenden, wird diese Klasse automatisch für uns eingeführt.

更优的解决方案是通过 spl_autoload_register 函数,将自定义的类加载程序作为 __autoload 的实现,以替代默认 __autoload() 模式函数或方法的行为。

所有 prependToLoaderStack() 方法:

    /**
     * Prepend the load method to the auto-loader stack. 设置自动加载方法。
     */
    protected function prependToLoaderStack()
    {
        // 将 AliasLoader 的 load 方法作为 __autoload 的实现
        spl_autoload_register([$this, 'load'], true, true);
    }

就是去完成这样的作用,将 AliasLoader->load() 方法作为自动加载程序的实现,在使用「外观」服务时动态引入这个类。

➤ 2. 支持外观服务别名

我们已经了解到当「外观」服务被使用时,由 AliasLoader->load() 去自动加载这个类。

与此同时,load 方法通过 class_alias($original, $alias) 函数完成别名注册。

这样,当我们使用 App 类时实际上就是在使用 Illuminate\Support\Facades\App 类。

很完美么,我们的「狗蛋」终于与「世界上最好的语言」画上了等号。你就是我,我就是你。

到这里其实已经完成了「外观」服务工作原理分析工作的 70%

探秘 Facade

最后我们将揭开 Facade 的神秘面纱,研究一下 Laravel 是如何实现 Facade 设计模式的。

我们拿 IlluminateSupportFacadesApp 外观服务开刀,去解开类似 App::make() 静态方法使用的奥秘。

深入 FacadesApp

<?php

namespace Illuminate\Support\Facades;

class App extends Facade
{
    /**
     * Get the registered name of the component.
     */
    protected static function getFacadeAccessor()
    {
        return &#39;app&#39;;
    }
}

我们看到它的实现内部仅仅定义了一个 getFacadeAccessor 方法,该方法的功能是获取已注册组件的名称 app;除此之外,一无所有。

看来在这里我们得不到什么有用的信息了。继续调查基类 IlluminateSupportFacadesFacade。如果你有去通便浏览全部的源码。

<?php

namespace Illuminate\Support\Facades;

use Mockery;
use RuntimeException;
use Mockery\MockInterface;

/**
 * @link https://github.com/laravel/framework/blob/5.6/src/Illuminate/Support/Facades/Facade.php
 */
abstract class Facade
{
    /**
     * Handle dynamic, static calls to the object.
     */
    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException(&#39;A facade root has not been set.&#39;);
        }

        return $instance->$method(...$args);
    }
}

你会发现这个 Facade 基类并没有定义类似 make 的方法,那么这里能够静态调用 App::make() 看来是需要从 __callStatic 着手才行。

不过在这里我们需要再次厘清一个事实:「外观」模式的功能是什么?

将使用者与子系统从直接耦合,转变成由「外观」类提供统一的接口给使用者使用,以降低客户端与子系统之间的耦合度。

这句话的意思就是我「外观」啥也不提供,就是一层对服务(或者说组件或接口)的封装,然后以统一的方式提供给你们外部调用。

好了现在我们来看看 Facade::__callStatic 是如何获取实际的服务并调用响应的方法的吧。

  • 首先,通过 getFacadeRoot 静态方法获取实际服务的实例对象;

  • 然后,调用实例对象的相关方法并返回处理结果。

<?php

namespace Illuminate\Support\Facades;

use Mockery;
use RuntimeException;
use Mockery\MockInterface;

abstract class Facade
{
    /**
     * Get the root object behind the facade. 从 facade 中解析出真实服务的对象
     */
    public static function getFacadeRoot()
    {
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }

    /**
     * Resolve the facade root instance from the container.me 从 Laravel 服务容器中解析出真实服务的对象
     */
    protected static function resolveFacadeInstance($name)
    {
        if (is_object($name)) {
            return $name;
        }

        if (isset(static::$resolvedInstance[$name])) {
            return static::$resolvedInstance[$name];
        }

        return static::$resolvedInstance[$name] = static::$app[$name];
    }
}

getFacadeRoot 解析对象的功能中我们可以看到:它会调用实现「外观」的 getFacadeAccessor 方法获取到组件(服务或者说接口)的名称;然后从 Laravel 服务容器 static::$app[$name](app 是在 RegisterFacades 中注册到「外观」中) 中解析出相关服务。

到这里,我们就将「外观」服务的基本工作原理给分析透彻了。

另外有关「外观」组件的一些细枝末节,如:

  • 在文档「Facades Vs. 辅助函数」一节提到的测试验证是如何实现的 Cache::shouldReceive('get')

  • 什么是「实时 Facades」。

还是需要你自行深入到 Facade 基类去一探究竟。

扫盲 ArrayAccess 接口

另外补充一个知识点就是关于 static::$app[$name] 这一句代码。你不经要问,这有啥好补充的呢,不就是一个简单获取数据么。

获取数据不假,简单也不假。

不过你仔细看一下,你会发现 static::$app 静态成员变量难道不是一个 \Illuminate\Contracts\Foundation\Application 实现实例么,怎么可以从对象中以数组的方式获取值呢?

这是因为我们的服务容器 Illuminate\Container\Container 实现了 ArrayAccess 接口。

该接口的功能是提供像访问数组一样访问对象的能力的接口,这样就可以像数组一样访问对象访问成员。

/**
 *@link https://github.com/laravel/framework/blob/5.6/src/Illuminate/Container/Container.php
 */
class Container implements ArrayAccess, ContainerContract
{
    /**
     * Get the value at a given offset. 获取一个偏移位置的值,实际上从容器中解析出服务。
     */
    public function offsetGet($key)
    {
        return $this->make($key);
    }
}

Laravel「外观」基本使用

外观服务的一个典型使用场景是在定义路由时使用 Route::get('/', ...)。这样一看似乎「Laravel 别名服务」也就不这么神秘了。

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er für das Studium aller hilfreich ist. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website.

Verwandte Empfehlungen:

Interpretation von Laravel Service Provider (ServiceProvider)

Laravel Core Interpretation Facades

Das obige ist der detaillierte Inhalt vonAnalyse des Fassaden-Erscheinungsbildsystems von Laravel. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn