源码分析--Laravel Collection
Laravel Collection 原理和用法解析。
Laravel: 11.x
PHP: 8.x
code: vendor/laravel/framework/src/Illuminate/Collections/Collection.php
docs: https://laravel.com/docs/11.x/collections
介绍
Illuminate\Support\Collection 类提供了一个流畅、方便的包装器来处理数据数组。Collection 可以看作是 PHP 数组的超级增强版。不仅保留了数组的所有基本功能,还提供了大量强大的方法,将复杂的数据操作转变为简单、优雅的链式调用,提高了开发效率和代码可读性。
在 Laravel 里面,Collection 随处可见
继承的类
ArrayAccess
PHP 内置接口,实现后可以让对象像数组一样操作。
CanBeEscapedWhenCastToString
定义了一个类在被强制转换为字符串(或调用 __toStirng)时,是否应该自动进行 HTML 转义(HTML escaping)。避免手动调用 htmlspecialchars 或类似函数,blade 模板在渲染数据也会检查是否实现了这个接口。
Enumerable
Enumerable 接口是框架中集合(Collections)相关功能的核心接口之一,它定义了用于操作和遍历集合的方法。比如 every、map、filter、reduce 之类的。主要可以对集合可以进行链式调用、数据操作和迭代等操作。这个类也继承了一些数组相关的类,如下:
Arrayable
Illuminate\Contracts\Support 定义的接口,有一个 toArray 方法。
Countable
PHP 内置接口,有一个 count 方法,返回对象的数量。
IteratorAggregate
PHP 内置接口,实现可以对其使用 foreach 语法。
Jsonable
Illuminate\Contracts\Support 接口,toJson 方法。
JsonSerializable
PHP 内置接口,可以 json 化。
使用的 Trait
EnumeratesValues
提供一系列用于枚举和处理值的方法。这里面使用了 HigherOrderCollectionProxy 代理,功能就是代理原来 Collection 自身的方法通过简化的方式调用,具体看下面。
HigherOrderCollectionProxy 大致原理:Collection 本身没有 filter, map, reduce 属性(注意这里是属性,不是方法),通过 EnumeratesValues 的__get() 方法调用 HigherOrderCollectionProxy 并设置 method 为 filter/map 等等,然后返回 HigherOrderCollectionProxy,当链式调用属性 active 时会通过 HigherOrderCollectionProxy 的 __get 去使用代理的 method,返回 Collection 类,循环往复。
Macroable
Macroable 允许为类动态添加方法,也就是「宏」,使类具有高度的可扩展性。通过使用 Macroable,可以在运行时给类添加自定义行为,而不需要修改类的源码。添加的方法支持静态调用和箭头调用。
LazyCollection
延迟计算(Lazy Evaluation)是一种优化技术,核心思想是「需要时才计算」。在 Laravel 的 Collection 中,主要通过 LazyCollection 实现。
它的主要原理如下
- 迭代器模式:使用 PHP 迭代器延迟计算
- 惰性求值:只在真正需要时计算
- 流式处理:一次处理一个元素
总结
Collection 有很多使用的方法,比如按照对象的某个元素分组 groupBy,分块 chunk,扁平化 flatten,函数式编程(map、filter、reduce、every…)。还了解到 data_set,data_get,date_forget helper 系列函数负责使用「.」符号处理嵌套的数组。
从源码角度上分析学到了 PHP 接口和 Trait 的结合使用,闭包的设计,__get()
__call()
__callStatic()
的动态调用,使用 func_num_args()
方法实现方法重载。
__get()
:当类不存在属性时调用这个方法__call()
:当方法不存在时调用这个方法__callStatic()
:当静态方法不存在时调用的方法func_num_args()
:返回函数的参数个数