Laravelのコレクション(その3:全データ取得)

0
79

Laravelコレクション掘り下げシリーズ第三弾。今回は本体配列の内容全体を取得するメソッドに関して確認していきます。
「要素の取得」では目的とする要素の指定方法に関して様々なパターンがありましたが、今回は対象が全データなのでその点ではあまりバリエーションがありません。全データ取得に属するメソッドの個性は出力形式にあります。

all

$result = $collection->all();

本体配列を配列形式で返します。

本メソッドに関する関心事は後述するtoArrayとの違い一点ではないでしょうか?
この点は知ってしまえば簡単な話で、本体配列内にオブジェクトを含む場合に、allはオブジェクト形式のままとし、toArrayではそれらオブジェクトも配列に展開します。

join

$result = $collection->join(',');
$result = $collection->join(',', ' and ');

本体配列の全要素を引数で指定した文字列で結合した1つの文字列として返します。

例えば下記のような本体配列を持つコレクションを考えます。

[
    1,
    2,
    3,
    4,
    5
]

上記に対して最初に示した2つの用例の実行結果はそれぞれ以下になります。

1,2,3,4,5
1,2,3,4 and 5

前者は単純にPHPのimplode関数と同じ挙動ですね。
特徴的なのは後者でしょう。多分に英語表記を意識した仕様ですね。最後の結合部分にのみ第二引数の文字列を適用し、それ以外は第一引数の文字列で結合すると言う仕様です。蛇足ながら第3引数以降に文字列を指定しても無視されました(処理自体は正常に動作します)。

しかし、後者のパターンって第二引数に「and」か「or」の二択くらいしか思いつかないのですが(私の拙い英語力では)。
加えて、このような処理を行いたいケース自体があまり想像できません。

なお、どちらの用法に関しても対象は要素が数字か文字列の一次元配列に限定されるようです。
要素がオブジェクトであったり、多次元配列の場合は空文字が返されます。
確かに構造的なデータをそのまま文字列化しろと言われても困るかと思いますね。

要素を結合して文字列化する仕組みとしては「サブセット取得」に分類しているimplodeメソッドもありますが、そちらでは構造化されたデータ内の特定の要素を指定しての結合が可能です。
名前的にもPHP関数と同じでイメージしやすいので、おそらくはimplodeを使用することの方が多いような気がします。

toArray

$result = $collection->toArray();

本体配列を配列形式で返します。

先にも触れたように、allとの違いは内包するオブジェクトも含めて配列化してくれる点です。

もう少し厳密に整理しておくと、ここで言う配列化可能なオブジェクトは「Arrayable」であるものとのことです。
「Arrayable」はinterfaceであり、以下のような定義になっています。

<?php
  
namespace Illuminate\Contracts\Support;

interface Arrayable
{
    public function toArray();
}

つまり、そのオブジェクト自身もtoArrayメソッドを持っていて、それにより自身を配列化できるものと言うことになります。
と言うことは、「Arrayable」でないオブジェクトを含む場合はallと同様にオブジェクトのまま出力されるんでしょうかね(確認していませんが)。

本メソッドはおそらくはコレクションを使う上で最も使用頻度が高いメソッドではないかと思います。ただ、それ故に要注意なメソッドでもあります。
コレクションにあまり馴染んでいなかった頃は、コレクション型のデータを取得すると速攻でtoArrayで配列化して、以降は慣れ親しんだ配列として処理すると言うようなことを行っていました。しかし、これではコレクションの恩恵を完全に放棄してしまっています。
何らかの必要性でtoArrayにより配列化する場合は、以降は内部データの参照や加工は必要ない(既にコレクションとしてやりたいことはやり尽くした)段階で行うくらいの心がけが必要かと思います。
なお、ログ採取等の目的で使うこともしばしばですが、それは別の話として。

toJson

$result = $collection->toJson();

本体配列をJSON化して返します。

オブジェクトも配列化された上でJSON化されます。
「Arrayable」でないものが混ざっていた場合はどうなるのか良く分かりませんが、逆にそのようなオブジェクトを含んだコレクションを安易にtoJsonでJSON化してはダメなのかもしれません。
toJsonでJSON化するコレクションに含まれるオブジェクトは、それ自身がどのような配列に変換されるべきかを認識しており、そのための手段(toArray)を提供している(Arrayable)と言うことが前提であるべきかと思います。それがオブジェクト指向におけるオブジェクトの在り方かと。

総括

今回は数的には少なかったですが、次に整理する予定の「サブセット取得」に分類しているメソッドの数が大量であるため、一旦ここで切っておきたいと思います。

普段何気なく使っているtoArrayの本来の意味(ArrayableであるものをArray化する)を改めて認識できたことが最大の収穫ですかね。

コレクションはtoArrayメソッドにより本体配列を配列化して提供してくれますが、その方法自体はコレクションが知っていれば良く、使う側は特にそこは関知しない。
コレクションの内情的には、要素がオブジェクト以外であればそのまま出力(配列)に反映し、オブジェクトであればそのオブジェクトが持つtoArrayの出力結果を反映する。その際にオブジェクトがどのように内部データを配列化するかはそのオブジェクトが知っていれば良く、使う側(コレクション)は特にそこは関知しない。
と言うように、良い意味での「責任転嫁」が連鎖している(と思われる)辺りがいかにもオブジェクト指向っぽいです。
コレクションのメソッドの仕様を確認すると言う本記事の趣旨からは若干外れた点で妙に感心してしまいました。

と言うことで、次回は「サブセット取得」に関するメソッドの整理を予定していますが、量が多いので始める前から少々食傷気味です…