📘

phpでファーストクラスコレクションを作る

2021/07/09に公開

概要

phpでファーストクラスコレクションを作ろうと思っても、配列の中身の型は言語仕様では縛れない。
可変長変数を使ったら配列の中身をforeachでいちいち確認したりしなくてすむ。

以下、AccountクラスのファーストクラスコレクションであるAccountsクラスについての実装を例とする。

パターン1: コンストラクタの引数を可変長変数にしてタイプヒントする

arrayから生成できても便利なのでfromArrayメソッドも作ってます

class Accounts
{
    /** @var Account[]  */
    private array $accounts;

    public function __construct(Account ...$accounts)
    {
        $this->accounts = $accounts;
    }

    static public function fromArray(array $accounts): self
    {
        return new self(...$accounts);
    }

    public function add(Account $account): self
    {
        return new self(...array_merge($this->accounts, [$account]));
    }
}
$account1 = new Account('ichiro');
$account2 = new Account('jiro');
$account3 = new Account('saburo');

$accounts = new Accounts($account1, $account2, $account3);
// もしくは
$accounts = Accounts::fromArray([$account1, $account2, $account3]);

パターン2: 可変長変数を引数に取るprivateメソッドを定義して、そのメソッド経由で値をセットする

class Accounts
{
    /** @var Account[]  */
    private array $accounts;

    public function __construct(array $accounts)
    {
        $this->setValue(...$accounts);
    }

    private function setValue(Account ...$accounts): self
    {
        $this->accounts = $accounts;
    }

    public function add(Account $account): self
    {
        return new self(array_merge($this->accounts, [$account]));
    }
}
$account1 = new Account('ichiro');
$account2 = new Account('jiro');
$account3 = new Account('saburo');

$accounts = new Accounts([$account1, $account2, $account3]);

パターン3: 可変長変数を引数に取る無名関数を定義して、その関数経由で値をセットする

パターン2とおなじやり方だが、コンストラクタ内で簡潔するのでこっちの方が個人的に好み

class Accounts
{
    /** @var Account[]  */
    private array $accounts;

    public function __construct(array $accounts)
    {
        $set_value = function (Account ...$accounts) {
            $this->accounts = $accounts;
        };
        $set_value(...$accounts);
    }

    public function add(Account $account): self
    {
        return new self(array_merge($this->accounts, [$account]));
    }
}
$account1 = new Account('ichiro');
$account2 = new Account('jiro');
$account3 = new Account('saburo');

$accounts = new Accounts([$account1, $account2, $account3]);

Discussion