こんにちは!バックエンド担当の永井です!

はじめに

PHPの場合、特定の型のオブジェクトの集合を表現する時に配列を使うことが多いと思うのですが、どうせ同じ型の集まりなのだから、他の言語でも良くあるような 型を制限 して扱いたいなと日頃から思っていました。
SPL辺りで用意してくれても良いのになと思っていたのですが、なかなか実装されないので自分で作ろうかと思っていたところに、素敵なライブラリ ramsey/collection を見つけたのでご紹介したいと思います。

ramsey/collection

Java Collection Framework にインスパイアされたというこのライブラリは、PHP7.2以上で動作します。
個人的に、JavaのCollection Frameworkはよく出来ていて良いなぁと思っていたので、この記述を見た時は期待が高まりました!
ただ、JavaのCollection Frameworkと比べるとまだまだ揃っているクラスが少ないので、今後に期待って感じかなと思います。

インストール方法

composerでサクッといけます。

$ composer require ramsey/collection

Collectionの使い方

まずは普通のCollectionクラスはこんな感じで使います。

今回はMemberクラスというのを用意して、こいつをコレクションとして扱いたいと思います。

<?php

namespace Qcmnagai\CollectionSample;

use DateTimeInterface;

class Member
{
    private $name;
    private $email;
    private $joinedAt;

    /**
     * Member constructor.
     * @param string $name
     * @param string $email
     * @param DateTimeInterface $joinedAt
     */
    public function __construct(string $name, string $email, DateTimeInterface $joinedAt)
    {
        $this->name = $name;
        $this->email = $email;
        $this->joinedAt = $joinedAt;
    }

    /**
     * @return mixed
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return mixed
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @return DateTimeInterface
     */
    public function getJoinedAt(): DateTimeInterface
    {
        return $this->joinedAt;
    }
}

なんてことないValueObjectなクラスですね。
こいつのコレクションクラスを作る場合はこんな感じです。

<?php

$memberNagai = new Member('nagai', 'nagai@example.com', new \DateTime('2015-07-01'));
$memberShiga = new Member('shiga', 'shiga@example.com', new \DateTime('2019-09-01'));
$memberSawai = new Member('sawai', 'sawai@example.com', new \DateTime('2017-10-01'));

$members = new Collection(Member::class);
$members->add($memberNagai);
$members->add($memberShiga);
$members->add($memberSawai);

分かりやすいですね。
ちなみに、add()を使わずに最初にガーッと追加することも出来ます。

<?php

$memberNagai = new Member('nagai', 'nagai@example.com', new \DateTime('2015-07-01'));
$memberShiga = new Member('shiga', 'shiga@example.com', new \DateTime('2019-09-01'));
$memberSawai = new Member('sawai', 'sawai@example.com', new \DateTime('2017-10-01'));

$members = new Collection(Member::class, [$memberNagai, $memberShiga, $memberSawai]);

最初に指定した型じゃないものを追加しようとすると、ちゃんと例外投げてくれます。

<?php

$members = new Collection(Member::class);
$members->add(new \DateTime());
Ramsey\Collection\Exception\InvalidArgumentException : Value must be of type Path\To\Member;

親切!

クラスじゃなくて、スカラー型にも対応しております。
文字列の場合は、こんな感じ。

<?php

$members = new Collection('string');

便利っす。
文字列の他にも PHPマニュアルの型のページに載っているほとんどの型には対応してそうです。
mixed にも対応していて、個人的にPHPっぽくて良いなって思いました。

Collection以外のクラスたち

  • 値の重複を許さないSetクラス群
  • PHPでいう連想配列的なMapクラス群
  • いわゆるキュー構造のQueueクラス群

全て型による制限を付けられるようになっています。
個人的に Java Collection Framework の Sorted 系があるともっと嬉しいなと思っているのですが、今後に期待しつつ、時間を見つけて自分でも試しに作ってみたいなと思いました。

おわりに

いかがでしたでしょうか。
クラスの内部で使うだけだったら、単なる配列でも良いかなと思いますが、色んな所で使われるようなものであれば、こういったライブラリを利用しても良いんじゃないかなと思います。