为什么 Laravel 的外观表现得像一个单身人士?

Nik*_*ili 1 php laravel

我知道 Laravel 使用门面。但基本上我无法理解他们为什么使用它。让我们来看看也许是 File 门面类。当他们已经有了 FileSystem 类时,为什么他们将 File 类作为外观?我们不能在我们的代码中写这样的东西吗?

$file = new \Illuminate\FileSystem();
$path = $file->get(public_path("test.txt"));
Run Code Online (Sandbox Code Playgroud)

但是 laravel 决定使用 File 门面类,之后我可以写这样的东西:

$path = File::get(public_path("test.txt")); 
Run Code Online (Sandbox Code Playgroud)

美在何处?如果您查看外观模式,它会为您提供更轻松的界面来完成大型工作,并且当您可以使用 2 行外观来完成时,它不会使用 10 行代码,但是 Laravel 的外观使其难以理解。

可能是因为他们制作了门面类,使其像单例一样工作,这是它令人惊奇的一面吗?但是为什么单身如此惊人?

我不明白 laravel 的外观是什么想法。

Has*_*der 8

Laravel有一个类似于Facade设计模式的特性,也称为Facades。这个名字可能会让你感到困惑,因为 Laravel 中的 Facades 并没有完全实现 Facade 设计模式。根据文档

Facades 为应用程序的服务容器中可用的类提供“静态”接口。

因此 Facade 将允许我们使用接口而不必担心这些接口背后的实际实现。让我们以 Laravel 缓存系统为例。当我们打电话$items = Cache::get('items:popular');

在这里,我们借助 Cache 外观从缓存中检索项目。

所有外观类都是从基础Facade类扩展而来的。只有一种方法,必须在每个门面类中实现:getFacadeAccessor(),它返回 IoC 容器内的唯一服务名称。所以它必须返回一个字符串,然后从 IoC 容器中解析出来。

这是Illuminate\Support\Facades\Cache门面类的源代码:

<?php 
namespace Illuminate\Support\Facade;
class Cache extends Facade 
{
    protected static function getFacadeAccessor()
    {
        return 'cache';
    }
}
Run Code Online (Sandbox Code Playgroud)

它看起来像我们调用静态方法get()缓存类,但正如我们已经看到有没有这样的静态的方法缓存类。这里的方法get()实际上存在于容器内部的服务中。所有的魔法都隐藏在基本的Facade 中类中。

Facade类中,我们有__callStatic()方法。__callStatic()每次调用外观上不存在的静态方法时都会触发。因此,在调用Cache::get('items:popular')我们进入这个方法之后,我们在 getFacadeRoot() 方法的帮助下解析了 IoC 容器外的外观后面的服务实例。这个方法的代码是

public static function __callStatic($method, $args)
{
    $instance = static::getFacadeRoot();

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

    return $instance->$method(...$args);
}
Run Code Online (Sandbox Code Playgroud)

方法getFacadeRoot()返回 Facade 后面的服务对象的实例。在这种情况下,它最终指向CacheManager类。在CacheManager类中,我们有一个getDefaultDriver()方法可以从.env文件中获取默认缓存配置。

public function getDefaultDriver()
{
    return $this->app['config']['cache.default'];
}
Run Code Online (Sandbox Code Playgroud)

获取默认缓存配置后,使用它的PHP魔术方法__call()尝试调用Concrete Classget()上的方法默认的缓存(Redis的,数据库,分布式缓存等)。

所以$items = Cache::get('items:popular');如果默认缓存发生变化,我们的原始调用不会改变。大多数人使用数据库作为开发缓存,使用redismemcached作为后端。这将是Laravel外立面的工作,找出哪些行动,以获得从缓存中的值进行。比如redisget()实现是

public function get($key)
{
    $value = $this->connection()->get($this->prefix.$key);

    return ! is_null($value) ? $this->unserialize($value) : null;
}
Run Code Online (Sandbox Code Playgroud)

虽然memacached 的get()实现是

public function get($key)
{
    $value = $this->memcached->get($this->prefix.$key);

    if ($this->memcached->getResultCode() == 0) {
        return $value;
    }
}
Run Code Online (Sandbox Code Playgroud)

同样,您可以使用另一个缓存具体类。Laravel会为您决定要调用的具体实现。