【Laravel9】Collectionクラスの中身を見る~flattenメソッド編~
はじめに
配列を操作するためのラッパークラスであるIlluminate\Support\CollectionクラスにはLaravel9では139個ものメソッドがあります。
Laravelを使用していたら見かけるであろう、map()やpluck()、merge()はCollectionクラスのメソッドです。
公式ドキュメントも貼っておきます。
今回はflattenメソッドが何をしているのか見ていきます。
環境
- Windows11(WSL2)
- PHP 8.2.1
- Laravel 9.50.1
- sail 2.6.1
flattenメソッドとは
Collectionクラスのflattenメソッドは多次元のコレクションを1次元化します。
また、引数$depthでどのネストまでを対象にするかを指定することができます。
動作確認
簡単なプログラムでflattenメソッドの動きを確認します。
$depth指定無し
まずはdepthを指定しない場合
$collection = collect([
'料理' => [
'中華' => [
'餃子' => [
'シソ餃子',
'肉餃子',
],
'天津飯'
],
'イタリアン' => [
'ピザ',
'リゾット'
],
'日本' => [
'味噌汁',
'寿司',
],
'台湾' => 'ルーローハン',
],
]);
$result = $collection->flatten();
dd($result);
Illuminate\Support\Collection {#280 ▼
#items: array:8 [▼
0 => "シソ餃子"
1 => "肉餃子"
2 => "天津飯"
3 => "ピザ"
4 => "リゾット"
5 => "味噌汁"
6 => "寿司"
7 => "ルーローハン"
]
#escapeWhenCastingToString: false
}
$depth指定有り
depth()の引数に2を指定します。
$collection = collect([
'料理' => [
'中華' => [
'餃子' => [
'シソ餃子',
'肉餃子',
],
'天津飯'
],
'イタリアン' => [
'ピザ',
'リゾット'
],
'日本' => [
'味噌汁',
'寿司',
],
'台湾' => 'ルーローハン',
],
]);
$result = $collection->flatten(2);
dd($result);
Illuminate\Support\Collection {#275 ▼
#items: array:7 [▼
0 => array:2 [▼
0 => "シソ餃子"
1 => "肉餃子"
]
1 => "天津飯"
2 => "ピザ"
3 => "リゾット"
4 => "味噌汁"
5 => "寿司"
6 => "ルーローハン"
]
#escapeWhenCastingToString: false
}
結果は上記のようになりました。
2階層までを1次元化するのでシソ餃子、肉餃子以外が1次元になります。
flattenメソッドの中身
Illuminate\Support\Collection::flatten
Collectionクラスのflattenメソッドは以下のようになっています。
public function flatten($depth = INF)
{
return new static(Arr::flatten($this->items, $depth));
}
引数depthのデフォルト値はINFという定数が指定されています。INFはPHPの定義済み定数で、意味的にはinfinity(無限)です。
new staticなのでflattenメソッドが呼び出されたときに、引数のArr::flattenをインスタンス化してreturnしています。
さらにIlluminate\Support\Arrクラスのflattenメソッドを追ってみます。
Illuminate\Support\Arr::flatten
Arrクラスのflattenメソッドは以下の通りとなります。
public static function flatten($array, $depth = INF)
{
$result = [];
foreach ($array as $item) {
$item = $item instanceof Collection ? $item->all() : $item; //①
if (! is_array($item)) {
$result[] = $item; //②
} else {
$values = $depth === 1 //③
? array_values($item)
: static::flatten($item, $depth - 1);
foreach ($values as $value) {
$result[] = $value;
}
}
}
return $result;
}
①多次元のコレクションにも対応させるための処理です。
三項演算子の$item instanceof Collectionで処理を分けているため以下のようなコレクションでも1次元化できます。
$collection = collect([
collect(['test1','test2']),
collect(['test3','test4']),
]);
$result = $collection->flatten();
dd($result);
Illuminate\Support\Collection {#276 ▼
#items: array:4 [▼
0 => "test1"
1 => "test2"
2 => "test3"
3 => "test4"
]
#escapeWhenCastingToString: false
}
②$itemが配列でない場合はそのまま値を結果にセットします
最初の例でいうと、'台湾' => 'ルーローハン',
のルーローハンが該当します。
③$itemが配列且つ$depthが1のときはPHP組み込み関数のarray_valuesで数字添え字付き配列を結果にセットするようになっています。
$depthが1より大きい又はデフォルト値のときはstaticで自身の関数を呼び出して再帰的に処理して、
static::flatten($item, $depth - 1);
と$depthから-1していてdepthが1になるまで1次元化を繰り返します。
デフォルト値のときは全て1次元化されるまで繰り返します。
まとめ
Collectionクラスのflattenメソッドは、$depthがデフォルト値であれば全て1次元化し、$depthに指定があれば、指定の階層まで再帰的に1次元化することが分かりました。
Discussion