エンジニアのひよこ_level10

毎日更新してた人。たまに記事書きます。

【PHP】イミュータブルなクラスを作ってみる【497日目】

始まりは突然に。

昨日のブログにツッコミが入りました(‘ω‘ )

なるほどたしかに!
changeStatusというフィールド値をUserに持たせたほうが、Userのフィールド値とか状態に触れる知識を外部に持たせないって出来ますね。
状態に対する関心も、あちこちに分散しない……!

ってことで、頂いたアドバイスを自分なりに解釈して実装してみる。
(で、出来たらちょっとレビューをお願いしてみる・・・!)

頂いたアドバイス

実装

class User {
    private $name;
    private $status;

    public function __construct(string $name, int $status) {
        $this->name = $name;
        $this->status = $status;
    }

    public function __set($name, $value) {
        throw new Exception('This object can't be set field value.');
    }

    public function setStatus(int $status) {
        return new User($this->name, $status);
    }

    public function setName(string $name) {
        return new User($name, $this->status);
    }
}

応用

フィールド値にインスタンスを持つ場合。
前に勉強したやつ実装してみる。

【デザパタ自作】イミュータブルパターン(インスタンス内包対応)【266日目】 - エンジニアのひよこ_level10

class User {
    private $name;
    private $status;

    public function __construct(string $name, Status $status) {
        $this->name = $name;
        $this->status = clone $status;
    }

    public function __set($name, $value) {
        throw new Exception('This object can't be set field value.');
    }

    public function setStatus(Status $status) {
        return new User($this->name, clone $status);
    }

    public function setName(string $name) {
        return new User($name, clone $this->status);
    }
}

感想?

こんな感じ・・・?
これで、たぶん値の変更は不可能になって、データは新しいオブジェクトを返すようになっているはず・・・?

使用感としても、ユーザーは内部に何を持ってるかを意識せず、関数だけ意識できる気がする。

// 全部違うインスタンスになる。たぶん変更出来ないはず
$user = new User('youkan', new Status(false));
$user = $user->setName('Uiro');
$user = $user->setStatus(new Status(true));

Tell Don't Askの観点とか知らない言葉が出てきてるので、いつか勉強したいというか、
早くぺちおぶ行きたいのに、Laravel JP Conferenceとかイベントに被るから行けなかった・・・(登壇者だからどうあがいても行けなかった)

また今度こそ、行きたいね・・・!