分析 Collection(2)

先大概列幾個與原生 PHP 函式相關的方法。

Native Collection
array_chunk() chunk()
array_combine() combine()
array_diff() diff()
array_flip() flip()
array_filter() filter()
array_map() map()
array_reduce() reduce()
array_slice() slice()
array_walk() each()

通常 Collection 的實作,都有加強原生對 array 處理的方便性,這些就不多做說明,來提一些比較有趣的。

transform()

這個方法跟 map() 其實是一樣的,但它會改變原本的物件的內容:

public function transform(callable $callback)
{
$this->items = $this->map($callback)->all();

return $this;
}

pipe()

這個 pipe 的意義,與 Bash 的 | 類似,把該物件交由 callback 處理

public function pipe(callable $callback)
{
return $callback($this);
}

tap()

public function tap(callable $callback)
{
$callback(new static($this->items));

return $this;
}

之前曾提過 tap() 函式。這個方法也是類似的概念,它的等價程式碼如下:

$callback = function($items) {
//
};

$collection->tap($callback);

tap($collection, $callback);

讓 collection 自帶 tap() 方法,會串聯方法或是語意,都會比原本的 tap() 函式來的好。

toBase()

這個方法是用在繼承 Collection 的類別如 Eloquent Collection,如果想轉成單純的 Collection 的話,可以使用這個。

public function toBase()
{
return new self($this);
}

曾有自定義類別是繼承 Collection 的,不過設計上比較單純,所以還沒用過這個方法。

wrap()unwrap()

wrap() 會使用 Collection 把傳入的參數包裝起來,unwrap() 則是解包裝。

public static function wrap($value)
{
return $value instanceof self
? new static($value)
: new static(Arr::wrap($value));
}

public static function unwrap($value)
{
return $value instanceof self ? $value->all() : $value;
}

其中會注意到,warp() 裡面還用到了 Arr::wrap(),因此非 array 的參數也可以正常使用。

// class Arr
public static function wrap($value)
{
if (is_null($value)) {
return [];
}

return ! is_array($value) ? [$value] : $value;
}

when()unless()

這兩個方法很有趣,when() 是當 $value 是 true 的時候,就會執行 callback;unless() 則相反。

public function when($value, callable $callback, callable $default = null)
{
if ($value) {
// 如果 $value 是 true 就執行 callback
return $callback($this, $value);
} elseif ($default) {
// 如果 $value 不是 true 且有 default callback 的話,就換執行 default callback
return $default($this, $value);
}

return $this;
}

public function unless($value, callable $callback, callable $default = null)
{
return $this->when(! $value, $callback, $default);
}

可以注意到上面 unless() 寫法很有趣,它把 $value 反相後丟到 when,即可做出 unless 的方法。這特性在 Laravel 也很常見,比方說 isEmpty()isNotEmpty()

public function isEmpty()
{
return empty($this->items);
}

public function isNotEmpty()
{
return ! $this->isEmpty();
}

可以看到 isNotEmpty() 其實就是 isEmpty() 的相反。

會這樣設計的原因是:用起來比較直覺語意,可以參考下面兩段程式碼即可了解:

if (!$collection->isEmpty()) {
//
}

if ($collection->isNotEmpty()) {
//
}

Laravel 框架很多設計都是環繞在直覺語意上的,非常值得參考。