LoginSignup
17
9

More than 5 years have passed since last update.

PHPで読取専用プロパティを手軽に実現する

Last updated at Posted at 2017-04-16

はじめに

ドメイン駆動開発ではimmutableなクラスを使う機会が少なくありませんが(ex.ValueObject)、実装が単純&面倒なあまりせっかちなプログラマの勤労意欲を阻害しがちです。「プログラマは怠惰であれ」の精神に基づき、PHPでインスタントにReadOnlyなクラスを実装する方法を考えてみましょう。

まずは教科書的に書いてみる

メンバをprivateにした上でgetterを作るパターン。
コンストラクタ以外のタイミングではメンバのセットを受け付けません。
作りが明快な一方、プロパティの数だけgetterを作る手間が発生します。
@property-readはIDE補完用の記述です。

Human.php
/**
 * @property-read string $name
 * @property-read int    $age
 */
class Human {

    /** @var string */
    private $name;

    /** @var int */
    private $age;

    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }

    public function getName() {
        return $this->name;
    }

    public function getAge() {
        return $this->age;
    }

}

Use.php

    $human = new Human('ほげ野ぴよ太', '48');

    $name = $human->getName();   //OK
    $human->name = 'ふが田ぴよ彦'; //NG

面倒なのでgetterを共通化する

マジックメソッドを利用したTraitを使い回せば、getterを個別実装せずともReadOnlyなプロパティを手軽に実装できます。(ポイントはアクセス不能なメソッドのハンドリングです)

ReadOnlyTrait.php
trait ReadOnlyTrait {

    //__getはアクセス不能なプロパティを参照した際に呼び出されるマジックメソッド
    public function __get($name) {
        return $this->$name;
    }

}

Human.php
/**
 * @property-read string $name
 * @property-read int    $age
 */
class Human {

    use ReadOnlyTrait;

    /** @var string */
    private $name;

    /** @var int */
    private $age;

    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }

}

Use.php

    $human = new Human('ほげ野ぴよ太', '48');

    $name = $human->name;   //OK
    $human->name = 'ふが田ぴよ彦'; //NG

注意点

privateだろうがprotectedだろうが問答無用で外からプロパティを読めてしまうので、隠蔽すべき項目は個別の取り回しが必要です(当たり前ですが)。使用前に必ず適切性を一考しましょう。

2017/4/23 追記

@tadsanの指摘事項を反映しました。private/protectedなプロパティを外部から読み込み可能にするという投稿で、同コンセプトのコードをより精緻に解説してくれています。みんなも参考にしよう!(すぐに使えるライブラリ付き!)

17
9
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
9