CollectionはLaravelの持つ配列をラッピングしたクラスです。Collectionを用いることによってPHPの素の配列操作よりも多彩な配列操作を一貫性を保ったまま容易に実現できます。
Illuminate\Support\Collectionクラスは配列データを操作するための、書きやすく使いやすいラッパーです。以下の例をご覧ください。配列から新しいコレクションインスタンスを作成するためにcollectヘルパを使用し、各要素に対しstrtoupperを実行し、それから空の要素を削除しています。
コレクション 5.7 Laravel
Collectionは素晴らしいですが、題名にあるisset()の関連部分では特殊な挙動を見せます。
$arr = ['hoge' => null]; dump(isset($arr['hoge']));// false dump(isset($arr['fuga']));// false $col = new \Illuminate\Support\Collection(['hoge' => null]); dump(isset($col['hoge']));// true dump(isset($col['fuga']));// false
Collectionを介したせいで結果が素の配列と異なってしまいました。これはCollectionのArrayAccessインタフェースの実装の仕方に原因があります。
ArrayAccessインタフェースはオブジェクトを配列として呼び出すためのインタフェースです。これを実装すると次の画像の様にオブジェクトを配列として呼び出せます。
PHP: ArrayAccess – Manual
ArrayAccessの中でissetと直接的に絡んでいるメソッドがoffsetExistsです。
このメソッドが実行されるのは、ArrayAccess を実装したオブジェクト上で isset() あるいは empty() を使用した場合です。
PHP: ArrayAccess::offsetExists – Manual
\Illuminate\Support\CollectionのArrayAccess::offsetExistsは次の様に実装されています。
/** * Determine if an item exists at an offset. * * @param mixed $key * @return bool */ public function offsetExists($key) { return array_key_exists($key, $this->items); }
$this->itemsがCollection内で扱われている配列です。これはkeyが存在すれば値がnullであってもissetでtrueを返すということです。このため
$col = new \Illuminate\Support\Collection(['hoge' => null]); dump(isset($col['hoge']));// true
となります。
一見バグの様に見えますが、Determine if an item exists at an offset.とコメントされている上、実装内容を
public function offsetExists($key) { return isset($this->items[$key]); }
と変えるとこの変更が原因でLaravel自体のテストで失敗が起きます。つまり仕様です。
このアンチパターンと化したisset()の代わりになる判定方法が次のコードです。
$col = new \Illuminate\Support\Collection(['hoge' => null]); dump($col->get('hoge') !== null);// false dump($col->get('fuga') !== null);// false
https://implode.io/5yDeL4
Collection中のgetメソッドを用います。getメソッドはキーの値を返すメソッドです。次の引用の様にキーが存在しない場合、例外でなくnullを返します。
これによりgetメソッドの返り値はキーの値がnullであっても、キーが存在しなくともnullになります。これでissetと同じく、変数がセットされていること、そしてNULLでないことを検査することができます。