final class Momoclo { public readonly string $name; public readonly string $color; public readonly int $age; public function __construct(string $name, string $color, int $age) { $this->name = $name; $this->color = $color; $this->age = $age; } } readonly property
final class Momoclo { public function __construct( public readonly string $name, public readonly string $color, public readonly int $age, ) { } } readonly property
プロパティが増えると…… final class User { public function __construct( public readonly int $id, public readonly string $familyName, public readonly string $givenName, public readonly EmailAddress $email, public readonly DateTime $birthday, public readonly string $postcode, public readonly Prefecture $prefecture, public readonly string $city, public readonly string $street, public readonly string $room, public readonly PhoneNumber $tel, public readonly bool $isActive, ...
readonly class final readonly class User { public function __construct( public int $id, public string $familyName, public string $givenName, public EmailAddress $email, public DateTime $birthday, public string $postcode, public Prefecture $prefecture, public string $city, public string $street, public string $room, public PhoneNumber $tel, public bool $isActive, ...
use Illuminate\Database\Eloquent\Model; final readonly class Item { public function __construct( public string $name, public int $price, ) { } } final class ItemRecord extends Model { // 略 } $record = ItemRecord::find(id: 17); $item = new Item( id: $record->id, price: $record->price, ); ORM からの変換
use Illuminate\Database\Eloquent\Model; final class ItemRecord extends Model { // 略 // ドメインモデルに変換するメソッド public function toDomain(): Item { return new Item( id: $record->id, price: $record->price, ); } } $item = ItemRecord::find(id: 17)->toDomain(); 解決策①:ドメインモデルへの変換メソッド
use Illuminate\Database\Eloquent\Model; final class ItemRecord extends Model { // 略 } final class ItemRepository { public function lookup(int $id): Item { return ItemRecord::find(id: 17)->toDomain(); } } 解決策②:リポジトリパターン
use \Illuminate\Contracts\Cache\Repository as CacheRepository; final readonly class Foo { private CacheRepository $cache; public function _construct() { $this->cache = Cache::store('array'); } public function getSomething(int $arg): int { return $this->cache->remenber($arg, 86400, function (int $arg): int { // 引数に対応して何かを計算して返す処理 return $arg ** 2; }); } } 解決策①:素直にフレームワークに頼る
final readonly class Foo { // キャッシュを保存・読み出ししてくれるクラスを独自に用意して利用する private CacheManager $cache; // 略 public function getSomething(int $arg): int { return $this->cache->getOrElse($arg, function (int $arg): int { // 引数に対応して何かを計算して返す処理 return $arg ** 2; }); } } 解決策②:キャッシュ専⽤のクラスを⽤意する
final readonly class Point { public function __construct(public int $x, public int $y) { } } $a = new Point(x: 3, y: 5); // $a と X 座標は同じで Y 座標が異なる Point オブジェクトを作成したい $b = new Point(x: $a->x, y: 7); ⼀部の値を変更したインスタンスを得る
final readonly class Person { public function __construct( public int $id, public string $familyName, public string $givenName, public int $age, // ... ) { } function aging(Person $person): Person { return new Person( id: $person->id, familyName: $person->familyName, givenName: $person->givenName, age: $person->age + 1, // ... ); } } プロパティが多いと⾯倒だし読みにくい
// Scala: case class case class Point(x: Int, y: Int) val a = Point(x = 3, y = 5) val b = a.copy(y = 7) // Kotlin: data class data class Point(val x: Int, val y: Int) val a = Point(x = 3, y = 5) val b = a.copy(y = 7) // Java 16 以降: Record public record Point(int x, int y) {} 他の⾔語の場合
abstract readonly class Model { public function copy(...$values): self { return call_user_func_array([new ReflectionClass(self::class), 'newInstance'], [ ...get_object_vars($this), ...$values, ]); } } final readonly class Point extends Model { // 略 } $a = new Point(x: 3, y: 5); $b = $a->copy(y: 7); 解決策①:⾃家製 copy メソッドを実装する
use Spatie\Cloneable\Cloneable; final readonly class Point { use Cloneable; public function __construct(public int $x, public int $y) { } } $a = new Point(x: 3, y: 5); $b = $a->with(y: 7); 解決策②:spatie/php-cloneable を使う
解決策③:withHoge メソッドを実装する use Spatie\Cloneable\Cloneable; final readonly class Item { use Cloneable; public function __construct( public string $name, public int $price, public Carbon $createdAt, public Carbon $updatedAt, ) { } public function withPrice(int $price): self { return $this->with(price: $price, updatedAt: Carbon::now()); } }