【问题标题】:Why is laravel mainly using Facades instead of singletons?为什么 laravel 主要使用 Facades 而不是单例?
【发布时间】:2021-09-03 14:39:45
【问题描述】:

读到这里你会发现外墙并不是真正的外墙

why does laravel's facade behave like a singleton?

Facades 上的所有方法都是静态的(去Illuminate\Support\Facades 看看自己)

有些别名实际上就是这样,例如普通类

'Arr' => Illuminate\Support\Arr::class,

作为外墙有什么意义?

【问题讨论】:

  • 你在问外墙存在的意义是什么?
  • 也许这对你有帮助 reddit.com/r/PHP/comments/nusb04/… 从那里引用“它们只是将全局状态引入你的应用程序的一种方式,隐藏在简单的伪装下。”

标签: laravel laravel-8


【解决方案1】:

为什么 laravel 主要使用 Facades 而不是单例?

Facades 是单例,因为它们的实现方式。

首先,让我们定义一些我们正在使用的术语:

Facade可以指两个东西:

  1. Laravel's Facades,一种用于方便开发人员的工具,也是依赖注入的替代方法
  2. facade design pattern。 Laravel 的门面不是门面设计模式的实现。对于那些刚接触 Laravel 但熟悉外观设计模式的人来说,这是一个常见的困惑点。 Laravel 的 Facades 最好被认为是 static proxies 到 Laravel 容器中的服务。

Singleton 是一种创建型设计模式,可让您确保一个类只有一个实例,同时提供对该实例的全局访问点。 (Source)

这些定义并不相互排斥。某些东西可以是一个外观一个单例(无论它们是否应该都是不同的对话)。

Laravel 的 Facades 在两种方面都是单例的:抽象的 Facade 类和 Laravel 的 IoC Container。

abstract Facade class - 所有单个 Facade 的父级 - 是 Facade 充当单例的主要原因。当调用 Facade 时,它​​会从 Laravel 的容器中解析其底层类并将其保存到本地静态属性中。后续调用将引用本地属性值,而不是再次从容器中解析。

Laravel's Inversion of Control Container 是 Facade 可以引用单例对象的另一种方式。当您将服务绑定到容器时,您可以使用Container::singleton() 确保服务在检索时始终解析为同一个实例。

我希望澄清一些东西可以同时是一个单例一个门面。

有些别名实际上就是这样,例如普通类

在此上下文中的别名只是对 PHP 的 class_alias() 的调用,是一种通过最小化完全限定的类名(命名空间 + 类名)来使 Facades 和其他类更易于使用的方法。无需use Illuminate\Support\Arr;,您可以在代码中只使用use Arr;\Arr::get() 而无需导入。这在 Blade 模板中特别有用。这些别名可用于但不限于 Facades。

如果所有函数都是静态的,为什么像 session() 这样的辅助函数都与 -> 一起工作,例如config()->set() vs config()::set()when the facade doesConfig::set()`?

只是目的和实施的不同。 Facade 是一个代理——所有交互都发生在 Facade 本身,但它代理对底层服务的请求。辅助函数不代理任何调用,它们只返回从容器中检索到的服务。

// Only interacts with the Facade class.
// set() is proxied via the magic __callStatic() method.
Config::set();

// config() returns an instance of the Config Repository class.
// Subsequent calls are directly on that instance.
// No magic methods used.
config()->set();

外观还附带一些模拟和测试实用程序,根据您的测试需求,它们可能会成为更好的解决方案。

【讨论】:

  • "因此它不能是单例"...外观有一个状态,即按照配置示例,它使用什么配置存储库。查看外观类,您将看到`protected static $resolvedInstance;`,因此外观就像单例一样是有状态的。如果我记得解释是别的东西,即您可以更好地测试外观。
  • 这很好,外墙确实存储了它们解析的实例。我已经修改了我的答案,用它来强调我原来的观点,即两者如何同时为真。
  • 奖励:如果所有函数都是静态的,为什么像 session() 这样的辅助函数都与 -> 一起工作,例如config()->set() vs config()::set() 当门面做 Config::set() 时?就像当你要实现自己的小有用函数时,比如akan(),它可以让你访问所有你不想写出或导入的烦人的长内容,你将如何实现它?
  • 我将其添加到我的答案中。 TL;DR:类似的最终功能(使用没有依赖注入的服务),但不同的实现。
猜你喜欢
  • 2017-07-02
  • 2020-08-10
  • 1970-01-01
  • 2011-02-27
  • 1970-01-01
  • 2022-11-17
  • 2011-02-15
  • 2013-01-04
  • 2013-12-07
相关资源
最近更新 更多