In this article, I'd like to talk about value objects. Value Object is an elementary class that contains mainly (but not only) scalar data.
Here's an example: class Percent { public readonly ?float $value; public readonly string $formatted; public function __construct(float $value) { $this->value = $value; if ($value === null) { $this->formatted = ''; } else { $this->formatted = number_format( $value * 100, 2 ). '%'; }} public static function from(?float $value): self { return new self($value); }}
Just imagine how the class would look like with attribute accessors: namespace App\Models; class IncomeStatement extends Model { public function pricePerShare(): Attribute { return Attribute::make( get: fn (int $value) => Millions::from($value)); } public function costOfRevenue(): Attribute {} public function grossProfit(): Attribute {} public function operatingExpenses(): Attribute {}}
The cast is almost identical to PriceCast: namespace App\Models\Casts; class MarketCapCast implements CastsAttributes { public function get($model, $key, $value, $attributes) { return MarketCap::from($value); } public function set($model, $key, $value, $attributes) { return $value; }}