Laravel 源码学习之 Collection
本系列文章,主要基于在查看社区文档时,可能因为看到某句话,一时兴起,想要一探究竟,如何实现,查看源码所得,也仅限于对源码的分析和学习,巩固知识,希望2019年持续学习,扎实基础。
将持续更新。
概述:
Illuminate\Database\Eloquent\Collection
继承了Laravel的集合基类Illuminate\Support\Collection
。 大多数集合方法会返回新的 Eloquent 集合实例, 但是 pluck, keys, zip, collapse, flatten 和 flip 方法除外,它们会返回一个 集合基类 实例。同样,如果 map 操作返回的集合不包含任何 Eloquent 模型,那么它会被自动转换成集合基类。
2019/1/19 第二更之闲言碎语
通过这两天阅读源码,最深的感受就是,对这个框架越来越了解,不是说仅仅于代码上,是在看一个新的部分的时候,能很快的举一反三联想到它大概是如何实现,然后去源码中验证,希望这种感觉会越来越好,2019,刻意学习,每日精进。
2019/1/18 第一更
-
关于
Eloquent\Collection
返回集合基类// Support\Collection::toBase() public function toBase() { return new self($this); }
map操作中会在执行完基类 map() 方法后,用后期动态绑定仍然返回一个
Eloquent\Collection
实例,然后调用contains()
方法:public function map(callable $callback) { $result = parent::map($callback); return $result->contains(function ($item) { return ! $item instanceof Model; }) ? $result->toBase() : $result; } public function contains($key, $operator = null, $value = null) { if (func_num_args() === 1) { if ($this->useAsCallable($key)) { $placeholder = new stdClass; return $this->first($key, $placeholder) !== $placeholder; } return in_array($key, $this->items); } return $this->contains($this->operatorForWhere(...func_get_args())); }
contains()
方法声明是传入键值对和操作符,但是它同时也支持仅传入一个值得情况,若 $key 不为回调,则仅用in_array
判断。若 $key 为回调,传入 callback 和stdClass instance
作为默认值给first()
,遍历集合的$items
,判断! item instanceof Model
。first()
返回非 Model 类型的值或者默认的 $instance,通过与默认值比较,得出在map()
操作后得到的集合中,是转为基类,还是返回$this
,以便后续链式调用。 -
关于
Support\Collection
的sum()
方法
看到sum()
方法属于偶然,源于这样一行代码:$average = collect([ ['foo' => 10], ['foo' => 10], ['foo' => 20], ['foo' => 40] ])->avg('foo');// 20
比较好奇,它是如何传入key去这样的一维数组中得到平均数。于是开始看源码:
public function avg($callback = null) { if ($count = $this->count()) { return $this->sum($callback) / $count; } }
那么一般都知道,平均数是由 sum 得来的,,,所以,调用了基类的
sum()
方法。public function sum($callback = null) { if (is_null($callback)) { return array_sum($this->items); } $callback = $this->valueRetriever($callback); return $this->reduce(function ($result, $item) use ($callback) { return $result + $callback($item); }, 0); }
那么 Laravel 中就是使用了非常多的 $callback 参数去适应各种输入,以达到灵活参数的目的,这就好比是 java 中的方法重载一样,只不过 php 是弱语言,对于参数类型没有严格限制而已。在这个方法中,如果不传参数,则类似于
array_sum([1,2,3]);//6
。
函数的返回值中写的很妙,在于将集合$items
数组属性的每一项扔进一个回调中得到想要的值并参与计算总和,那么这个回调从哪儿来呢?从传入的参数中获得,因此,调用基类的valueRetriever($callback)
,该方法返回一个匿名函数:protected function valueRetriever($value) { if ($this->useAsCallable($value)) { return $value; } return function ($item) use ($value) { return data_get($item, $value); }; }
如果参数非函数,则造一个匿名函数,接收一个一维数组或者对象,返回键为 $value 的数组值或者对象的 $value 属性给上层调用去参与计算 sum。嗯,就是酱紫,总结就是:可传入参数有null,回调,或者指定值。而集合的
$items[]
通常有什么呢:基本类型值,数组(可多维,data_get()函数使用点语法
),对象。
本作品采用《CC 协议》,转载必须注明作者和本文链接