Laravel 底层: Illuminate\Support 下 Macroable、 Fluent、Manager、Arr、Str、Collection 和 Helpers

通常,您的项目中包含一些需要在整个项目中重用的代码。 Laravel 框架本身也是如此。将代码提取到可重用的类中是一种很好的做法。像数组和“点”符号这种,因为 Laravel 允许您在各个地方使用“点”符号从嵌套数组中获取特定值、配置、请求参数或翻译等。因此 Laravel 为我们提供了一个 Arr类,该类具有一些对数组的通用操作,例如数据检索使用“点”表示法等。还有 Laravel 的支持组件。支持组件是各种类或 trait,其逻辑在整个框架中都可以复用。Laravel 有各种各样的支持类,我们只讨论Fluent 类,Manager,字符串和数组类,Collection和 helper 等这些称为宏的类。我们将逐一介绍它们的用途,并说明它们的使用场景,并为他们讲解一个用例。所有这些都放置在 Illuminate \ Support 命名空间中。 请注意,所有这些类都可以在您的应用中使用,而不仅限于框架本身。

宏 (Macros)

宏是一种挂接到框架并扩展某些附加功能而无需显式继承该类的方法。 许多Illuminate 组件都使用了 Macroable 特性,该特性允许您为类扩展更多功能。 如果我们深入研究代码并了解其特征,则可以看到静态属性$macros。 该静态属性的作用是 全局访问。 如果将宏分配给 Collection 类,则所有 Collection 实例将能够访问同一宏。

使用方法

注册宏

通过调用静态方法 macro($name,$macro) 将宏绑定到类中。 该方法从字面上通过键 $name$macro(关闭执行功能)绑定到 $macros 数组中。 用它可以扩展更多用法,例如,像文档中所述的 Collection 类。 请注意,这通常是在服务提供者中完成的。

macro详解

我们还可以看到 __call__callStatic 魔术方法。 只要在类上调用了不可访问的方法,PHP 就会自动调用这两个魔术方法。 我们想重写它以查看宏是否存在(static :: hasMacro($ macro),如果存在,则从数组中解析 macro 并调用它。 macro 通常是个可以被任何类调用的闭包。 请注意,如果愿意,可以通过调用 mixin 方法在另一个对象中建立宏。 您可能没有注意到,在 Closure 中宏调用 $this 将访问该类本身的当前实例。 这怎么可能? 我如何使用 $this 访问 Closure 中的对象的属性和方法? 好吧,PHP的闭包中有一种称为 bindTo 的方法,而 Laravel 则利用了这种方法。 它将当前宏对象绑定到 Closure ,因此 $this 引用类本身,而不是 Closure。

冲突

如果使用Macroable 特性的类具有 __call 方法,则将发生冲突。 两种方法都不能被调用,因此当我们使用Macroable 时,我们应该将 Macroable__call 方法重命名为其他名称,但是请确保在对象的 __call 方法中调用你重命名的方法。 可以在 Cache\Repository 类中看到示例。 我们导入 trait,同时将 __call 重命名为 macrocrock。 然后在 Repository 的__call 中,如果类具有宏,请确保调用 macroCall方法 ,否则默认调用b本地方法,这样既可解决冲突。

注意: 不要过度使用它。 如果您有很多宏,或者有一些非常复杂的逻辑,那么继承类并执行相应的逻辑要比用宏扩展服务提供者要好得多。

我比较喜欢使用一个宏来检查 Request 类,以确定是否选中了表单中的复选框:

Request::macro('checked', function ($attribute) {
    return in_array($this->input($attribute, false), [true, 1, '1', 'on']);
});

Fluent

我也是最近才发现的,这让我震惊。到底是啥呢?大家都知道当你想在应用程序中存储一些数组元素时必须构建所有样板。
假设您有一些网站设置,它们作为键值对存储在数据库中。您可能需要建立一个具有 getter 和 setter 方法的类,在这种情况下,getter 需要返回一些默认值,以防请求的数据不存在或者拦截非法访问。例如,不存在但返回null的数组值。然后,您可能需要实现各种接口,因为要访问带有数组符号的数据,例如 $settings ['timezone'] 或对象符号 $settings-> timezone 。然后,您需要定义返回的 JSON 响应时的数据结构。这都是您需要实现的一些通用操作。 Illuminate \ Support \ Fluent 提供了基础代码,如果您具有 Settings 类这样的类,则可以继承 Fluent 类并添加一些其他方法(例如 savepersist )或类似的更新数据库的方法,并重写构造函数,从数据库中加载数据并将其存储到对象中,您可以很快就建立了原始键值对存储。

Manager

Manager 是一个类,它可以指示当前将哪个驱动程序用于应用程序的某些功能。 举个例子更好阐述, 比如说缓存:您可以使用多个缓存驱动存储,例如memcached,redis,文件,数据库等。缓存管理器对 Laravel 说:好的,您现在使用 redis 驱动存储,但是如果用户需要使用文件驱动存储。 驱动程序上有很多 Illuminate 组件可以使用:session,身份验证,队列等。您可以在应用程序中使用相同的模式。 举个例子,比方说:假设您正在对一些用户内容进行排名。 您将创建一个名为 Ranker 的类,该类继承了Illuminate\Support\Manager。您在 Ranker 里实现了多种排序算法,并且每种算法实现都是所谓的驱动程序,您可以根据需要更换它们。 它们都有 RankAlgorithm 接口规定的相同方法。 有一天,您要使用一种算法,然后,如果由于某种原因而停止工作,换用另一种算法,依此类推。也许有更好的实现方法,但是哦,Laravel 已经为您准备了 Illuminate\Support\Manager 类,允许您基于驱动程序实现。如您所见,如果要扩展此类,则需要实现 getDefaultDriver 方法来确定默认情况下将使用哪个驱动程序。 例如上文提到的缓存案例,将从配置文件中读取配置,来确定应用将使用哪个缓存驱动。 然后,一旦在 Ranker 类上调用了一个方法(如rankContent),则默认驱动程序为 AlgorithmA,则 Ranker 将从当前激活的驱动程序委托给 rankContent 方法。 现在,当您想更改另一个驱动程序时,将 getDefaultDriver 方法更改为使用 AlgorithmB 驱动即可。 Ranker 类不关心正在使用哪个驱动,并且不需要更改其他任何内容。

注册驱动

在 Manager 调用驱动方法之前,它需要知道都有哪些驱动程序。 我们需要注册它们。 当在 Ranker 类上调用一个方法时,它将在 driver() 返回的任何值上调用该方法。 现在我们注意到 driver() 方法应该返回当前正在使用的驱动程序的实例。 在这里可以看到 driver() 方法,可以看到它正在调用createDriver 方法。 createDriver 方法会执行创建新驱动实例的逻辑。 它使用PHP动态方法魔术命名,并且需要遵守以下命名约定:

$method = 'create'.Str::studly($driver).'Driver';

if (method_exists($this, $method)) {
    return $this->$method();
}

因此,如果您具有名为AlgorithmA,AlgorithmB等的驱动程序,将被调用并创建它们的方法名为:createAlgorithmADriver 。此方法应返回该驱动程序的新实例。 创建新的驱动程序实例后,Ranker(管理器)将仅调用该驱动程序类上的方法。

扩展自定义驱动

Manager 类提供了与 Macros 类似的 extend 方法,允许开发人员动态注册自定义驱动程序。 在类上创建驱动程序之前,它将检查自定义驱动程序是否存在,如果存在,则调用自定义驱动。

Arr & Str

Laravel 的 Arr 和 Str 类提供了一些处理字符串和数组的方法。 请注意,Str类是一大堆静态方法,因为字符串是不可变的,因此它接收一个字符串并返回一个新的修改后的字符串,而输入内容保持不变。 Arr 类是在数组上执行操作的助手函数类。例如随机取一个数组元素,最后一个数组元素,第一个数组元素,第n个数组元素,交叉连接两个数组,转换为“点”表示法。 不要害怕使用,使用这个类非常容易实现。

集合

我相信这不需要介绍。但注意有两个集合类 Illuminate\Support\Collection 和 Illuminate\Database\Eloquent\Collection 。后者继承前者,且在你从数据库获取记录时返回。它包含一些附加的功能,像 load (渴求式加载模型关联), loadMissing (一样的东西但只加载未加载关联)等等。它也有 find 方法(注意这和 User::find($id) 不是一回事)。前者操作集合实例(意味着你所有的数据已从数据库获取而后者执行只选择指定 ID 项目的查询。通览 Eloquent 集合方法,你会发现一些酷炫的东西,如 modelKeys() 方法只返回(摘取)模型的主键(通常为 ID 集), fresh() 方法重载查询。你会发现自己大多于模型改变但需要获取一个新实例去看看数据有否在数据库持久化时在单元测试中使用它。还有大量非常有用的方法,像 makeHidden 和 makeVisible 用于当前集合实例(不是所有实例)隐藏模型特定属性。你可以在文档中发现更多东西。

自定义集合

您不知道吧?我们还可以通过扩展基类来创建自定义 Collection 类。 如果您需要将模型作为自己的集合的实例进行某些骚操作,这是很适用的。 Jeffrey Way 在 threaded comments 中使用了一个自定义集合的示例,集合中具有root方法和嵌套方法。 然后,如果您需要模型(例如User)返回自己的集合(例如UserCollection)的实例,则只需返回 new UserCollection($models) 就可以在用户模型中覆盖 Laravel 的newCollection(array $ models = [])方法 。

助手函数

大量的助手函数有时会非常有用。 有许多您可能不知道的助手函数。 例如:您听说过 blank($ value) 帮助函数吗? 还是有 value($ value)? 是的,有很多很棒的助手函数,而且由于它们的文档非常详细,因此我不会对其进行深入研究。

今天就这样,希望您对 Laravel 框架有了新的了解,并能很好地使用我向您介绍的这些类和功能!

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://crnkovic.me/laravel-behind-the-s...

译文地址:https://learnku.com/laravel/t/42944

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 1
qiuyuhome

很实用的文章.

感谢翻译.

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!