案件の中で、Value Objectを使用している箇所がいくつかあったのでまとめました。
Value Object(バリューオブジェクト) とは、
- 値をクラスにすること
- 値を変更したくなったら、バリューオブジェクトごと置き換えること
- どの箇所からでも再利用できること(バリューオブジェクト内のデータを使うので、データの値を担保できる)
と自分は認識しています。
例として、Userモデルを挙げます。
Userモデル |
---|
id |
name |
tel |
name
はその人の名前を表すものなので、バリューオブジェクトにする必要はないと思います。
下記あたりが、バリューオブジェクトにしやすいものと思います。
- CRUDするときに、変な値で登録させたくないもの
- typeが存在するもの(性別や、血液型など)
例として、Userモデルの中の、tel
をバリューオブジェクトにしてみます。
<?php
class Tel
{
const DEFAULT_TEL = '00000000000';
/** @var string */
private $tel;
/** @param string $tel */
public function __construct(string $tel)
{
// 数字以外の入力だったらエラー出すとか、文字数制限とか
if(xxxx){
// throw Exception
}
$this->tel = $tel;
}
/* @return string */
public function getValue(): string
{
return $this->tel;
}
}
このようになりました。telをクラス化しています。
値をクラス化することによって、Telをインスタンス化した時に、意図しない値が入るのを防ぐことができます。
意図しない値が入った場合例外を投げるので、エラー原因の特定につながります。
使い方
CRUD処理時など
User::register(
'test_name',
new Tel('090xxxxxxxx'),
....
)
これにより、new Tel('aaaaaa')
と 意図しない値が入ってもエラーで弾くことができます。
引数として使うときなど
public function findFirstByTel(Tel $tel)
{
return User::where('tel', $tel->getValue())
->get()
->first();
}
バリューオブジェクトを呼び出すとき
(new Tel('00000000000'))->getValue();
コレだとピンとこないので、
例えばUserモデルをモデリングしてみます(言葉合ってるかわからないです)
class UserEntity
{
private ?int $id;
private string $name;
private Tel $tel;
public function __construct(
$id,
$name,
$tel
) {
$this->id = $id;
$this->name = $name;
$this->tel = new Tel($tel);
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function getTel(): Tel
{
return $this->tel;
}
}
$entity = new UserEntity(null,'test_name','09012345678');
var_dump($entity->getTel()->getValue());
--> 09012345678
のような形で値を取ることができます。
この辺、DDDとも絡んでる気がするのですが、解釈人それぞれなのでこれ以上は追求しないです。(個人の感想です)