【问题标题】:why does laravel's facade behave like a singleton?为什么 laravel 的门面表现得像一个单例?
【发布时间】:2019-04-24 02:04:18
【问题描述】:

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

$file = new \Illuminate\FileSystem();
$path = $file->get(public_path("test.txt"));

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

$path = File::get(public_path("test.txt")); 

美在哪里?如果您查看外观模式,它为您提供了更简单的界面来完成大工作,而不是使用 10 行代码,而您可以使用 2 行代码来完成外观,但是 laravel 的外观使其难以理解。

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

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

【问题讨论】:

标签: php laravel


【解决方案1】:

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

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

所以 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';
    }
}

看起来我们正在调用 Cache 类的静态方法 get(),但正如我们所见,在 Cachestatic 方法/strong> 类。这里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);
}

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

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

获取默认缓存配置后,使用__call()的PHP魔术方法尝试在默认缓存(redis、数据库、memcached等)的具体类上调用get()方法。

因此,如果默认缓存更改,我们对 $items = Cache::get('items:popular'); 的原始调用不会更改。大多数人使用 database 作为开发缓存,使用 redismemcached 作为后端。 Laravel Facades 的工作是找出要执行哪些操作以从缓存中获取值。例如。 redisget() 实现是

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

    return ! is_null($value) ? $this->unserialize($value) : null;
}

memacachedget() 实现是

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

    if ($this->memcached->getResultCode() == 0) {
        return $value;
    }
}

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

【讨论】:

    猜你喜欢
    • 2012-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-02
    • 1970-01-01
    • 2021-05-02
    • 2016-09-04
    • 2016-08-28
    相关资源
    最近更新 更多