allメソッド Collectionメソッドソースコードリーディング100本ノック1本目
メソッド概要
allメソッドはコレクションの裏の配列表現を返します。
<?php collect([1, 2, 3])->all(); // [1, 2, 3]
裏の配列表現なんて仰々しい事を言っていますが、単純にコレクションの中身を配列で返すだけのメソッドです。
ソースコードリーディング
allメソッド
では早速、ソースコードリーディングをやって行きましょう。
<?php /** * Get all of the items in the collection. * * @return array */ public function all() { return $this->items; }
items
プロパティの値を取得する。以上。第3部完ッ!!
…これだけだと切なすぎるので、items
プロパティに何の値が代入されているのか construct
を見ましょう。
Collection の construct
<?php /** * Create a new collection. * * @param mixed $items * @return void */ public function __construct($items = []) { $this->items = $this->getArrayableItems($items); }
$items
を引数にして、getArrayableItems
メソッドを呼び出しています。
とりあえず getArrayableItems
メソッドの中身を覗きましょう。
getArrayableItemsメソッド
<?php /** * Results array of items from Collection or Arrayable. * * @param mixed $items * @return array */ protected function getArrayableItems($items) { if (is_array($items)) { return $items; } elseif ($items instanceof self) { return $items->all(); } elseif ($items instanceof Arrayable) { return $items->toArray(); } elseif ($items instanceof Jsonable) { return json_decode($items->toJson(), true); } elseif ($items instanceof JsonSerializable) { return $items->jsonSerialize(); } elseif ($items instanceof Traversable) { return iterator_to_array($items); } return (array) $items; }
Collection
や Arrayable
から配列を作成するメソッドのようです。
条件式が複数あるので、一つずつ何をしているのか処理を追っていきましょう。
条件式:is_array($items)
<?php if (is_array($items)) { return $items; }
$items が配列だったら、そのまま $items を返します。 配列なら、わざわざ変換する必要はありませんからね。
条件式:$items instanceof self
<?php } elseif ($items instanceof self) { return $items->all(); }
$items
のインスタンスが self
( Collection
) だったら、all
メソッドを実行しその返り値を返します。
ここで、ちょっとした例を出してみます。
<?php // IN: $items = new Collection([1]) $this->items = $this->getArrayableItems(new Collection([1])); $this->items = new Collection([1])->all(); $this->items = $this->getArrayableItems([1]); $this->items = [1]; // IN: $items = new Collection(new Collection([1])) $this->items = $this->getArrayableItems(new Collection(new Collection([1]))); $this->items = new Collection(new Collection([1]))->all(); $this->items = $this->getArrayableItems(new Collection([1])); $this->items = new Collection([1])->all(); $this->items = $this->getArrayableItems([1]); $this->items = [1];
つまり、2次元の Collection
でも3次元の Collection
でも、1次元の Collection
にしてくれます。以下が実際に実行した結果です。
<?php dd(new Collection(new Collection([1]))); Collection {#450 ▼ #items: array:1 [▼ 0 => 1 ] } dd(new Collection(new Collection(new Collection([1])))); Collection {#450 ▼ #items: array:1 [▼ 0 => 1 ] }
条件式:$items instanceof Arrayable
<?php } elseif ($items instanceof Arrayable) { return $items->toArray(); }
$items
のインスタンスが Arrayable
だったら、toArray
メソッドを実行しその返り値を返します。
Arrayable
Arrayable
は、Laravel
が提供している interface
です。
<?php namespace Illuminate\Contracts\Support; interface Arrayable { /** * Get the instance as an array. * * @return array */ public function toArray(); }
toArray
メソッドのみが定義されています。
別クラスに Arrayable
を implements
した上で、変換処理を記述した toArray
メソッドを実装する、という使い方でしょうか。
配列じゃない別クラスでも toArray
メソッドを使うことで、配列へ変換できるようにするため用意されている interface
のようですね。
条件式:$items instanceof Jsonable
<?php } elseif ($items instanceof Jsonable) { return json_decode($items->toJson(), true); }
$items
のインスタンスが Jsonable
だったら、json_decode
関数を実行しその返り値を返します。
json_decode
関数の第二引数が true
なので、$items
は配列にデコードされます。
Jsonable
jsonable は、 Laravel が提供している interface です。
<?php namespace Illuminate\Contracts\Support; interface Jsonable { /** * Convert the object to its JSON representation. * * @param int $options * @return string */ public function toJson($options = 0); }
toJson
メソッドのみが定義されています。
こちらも別クラスに Jsonable
を implements
した上で、変換処理を記述した toJson
メソッドを実装する、という使い方でしょうか。
json
形式じゃない別クラスでも toJson
メソッドを使うことで、json
形式へ変換できるようにするため用意されている interface
のようですね。
Arrayable
とちょっとだけ似ている気がします。
条件式:$items instanceof JsonSerializable
<?php } elseif ($items instanceof JsonSerializable) { return $items->jsonSerialize(); }
$items
のインスタンスが JsonSerializable
だったら、jsonSerialize
メソッドを実行しその返り値を返します。
JsonSerializable
JsonSerializable
は php
が提供している interface
です。 ( PHP: JsonSerializable - Manual )
<?php /** * Objects implementing JsonSerializable * can customize their JSON representation when encoded with * <b>json_encode</b>. * @link http://php.net/manual/en/class.jsonserializable.php */ interface JsonSerializable { /** * Specify data which should be serialized to JSON * @link http://php.net/manual/en/jsonserializable.jsonserialize.php * @return mixed data which can be serialized by <b>json_encode</b>, * which is a value of any type other than a resource. * @since 5.4.0 */ public function jsonSerialize (); }
jsonSerialize
関数のみが定義されています。( PHP: JsonSerializable::jsonSerialize - Manual )
別クラスに JsonSerializable
を implements
した上で、 jsonSerialize
関数を定義し、配列への変換処理を記述する。
使い方自体は Arrayable
や Jsonable
と一緒のようですね。
条件式:$items instanceof Traversable
<?php } elseif ($items instanceof Traversable) { return iterator_to_array($items); }
$items
のインスタンスが Traversable
だったら、iterator_to_array
関数を実行しその返り値を返します。
Traversable
Traversable
は php
が提供している interface
です。( PHP: Traversable - Manual )
<?php /** * @link https://wiki.php.net/rfc/iterable */ interface iterable {} /** * Interface to detect if a class is traversable using &foreach;. * @link http://php.net/manual/en/class.traversable.php */ interface Traversable extends iterable { }
iterable
を継承していることと( PHP: rfc:iterable )、コメントの内容から foreach
で繰り返し可能なクラスに実装するようです。
抽象 interface
なので Traversable
単体では動きません。ですので、Traversable
を継承している Iterator
もしくは IteratorAggregate
に、foreach
をした時の細かい挙動を実装する必要があります。
その上で、iterator_to_array
を使って配列へと変換していきます。( PHP: iterator_to_array - Manual )
<?php /** * Copy the iterator into an array * @link http://php.net/manual/en/function.iterator-to-array.php * @param Traversable $iterator <p> * The iterator being copied. * </p> * @param bool $use_keys [optional] <p> * Whether to use the iterator element keys as index. * </p> * @return array An array containing the elements of the iterator. * @since 5.1.0 */ function iterator_to_array ($iterator, $use_keys = true) {}
条件式:上記に当てはまらないとき
<?php return (array) $items;
上記に当てはまらなかった時は、配列に漢のキャストをします。
最後に
と言うわけで、Collection
メソッドソースコードリーディング100本ノック1本目が終わりました!
all
メソッドの内容だけでは寂しいと深掘っていったら、Laravel
どころか php
の内部実装まで触れてしまいました。
次は avg
と average
メソッドです!
マサカリや「ここちげえぞ!!!」と言う怒りのコメントまで、お待ちしております!