はじめに
保守的性の高いコードの書き方を調べているとイミュータブルなオブジェクトに関する話題を見つけました。
調べてみる
(そもそも)ミュータブルとは
- mutableは、可変という意味
- インスタンス(オブジェクト)の状態を変更できるインスタンス(オブジェクト)
- 想定していない更新が起こる可能性があるためイミュータブルより安全性が低い
(本題の)イミュータブルとは
- immutableは、不変という意味
- インスタンス(オブジェクト)の状態を変更できないインスタンス(オブジェクト)
- 変数に対して再代入をすることができないため、想定していない更新を防ぐことができる。ミュータブルより安全度が高い
書いてみる
Sale.php
class Sales {
private $price;
public function __construct(int $price){
$this->price = $price;
}
public function getPrice(): int {
return $this->price;
}
public function setPrice(int $price): void{
$this->price = $price;
}
}
$payment1 = new Sales(100);
echo $payment1->getPrice(); // 100
$payment2 = $payment1->setPrice(200);
echo $payment1->getPrice(); // 200
↑$payment2
への代入で$payment1
の値が書き換わっていることが分かる。setPriceメソッドのようにオブジェクトの状態を変更できるメソッドのことを「破壊的なメソッド」という。
イミュータブルなオブジェクトの実装では、この破壊的なメソッドによる代入を防ぐため、
セッターで値を入れる際は、新しいインスタンスを作成する。↓
Sales2.php
class Sales2{
private $price;
public function __construct(int $price) {
$this->price = $price;
}
public function getPrice(): int {
return $this->price;
}
public function setPrice(int $price): self {
return new self($price);
}
}
$payment1 = new Sales2(100);
echo $payment1->getPrice(); // 100
$payment2 = $payment1->setPrice(200);
echo $payment1->getPrice(); // 100
↑$payment2
への代入で$payment1
の値が書き換わらなくなった。
これで意図しない代入により途中で値が書き換わっていることを恐れずに済む。