laravel-value-objects

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Laravel Value Objects

Laravel Value Objects

Value objects are simple, immutable objects representing domain concepts.
Related guides:
  • DTOs - DTOs are for data transfer, value objects for domain concepts
值对象是代表领域概念的简单、不可变对象
相关指南:
  • DTOs - DTOs用于数据传输,值对象用于领域概念

When to Use

何时使用

Use value objects when:
  • Complex domain value with behavior
  • Immutability required
  • Rich validation logic
  • Need equality comparison
  • Encapsulating domain rules
Use DTOs when:
  • Transferring data between layers
  • No domain behavior needed
  • See DTOs
在以下场景使用值对象:
  • 带有行为的复杂领域值
  • 需要不可变性
  • 丰富的验证逻辑
  • 需要相等性比较
  • 封装领域规则
在以下场景使用DTOs:
  • 在各层之间传输数据
  • 无需领域行为
  • 查看 DTOs

Simple Value Object

简单值对象

php
<?php

declare(strict_types=1);

namespace App\Values;

use App\Enums\ProcessResult as ProcessResultEnum;

class ProcessResult
{
    public function __construct(
        public readonly ProcessResultEnum $result,
        public readonly ?string $message = null,
    ) {}

    public static function success(?string $message = null): self
    {
        return new self(ProcessResultEnum::Success, $message);
    }

    public static function skip(?string $message = null): self
    {
        return new self(ProcessResultEnum::Skip, $message);
    }

    public static function fail(?string $message = null): self
    {
        return new self(ProcessResultEnum::Fail, $message);
    }

    public function isSuccess(): bool
    {
        return $this->result === ProcessResultEnum::Success;
    }

    public function isFail(): bool
    {
        return $this->result === ProcessResultEnum::Fail;
    }
}
php
<?php

declare(strict_types=1);

namespace App\Values;

use App\Enums\ProcessResult as ProcessResultEnum;

class ProcessResult
{
    public function __construct(
        public readonly ProcessResultEnum $result,
        public readonly ?string $message = null,
    ) {}

    public static function success(?string $message = null): self
    {
        return new self(ProcessResultEnum::Success, $message);
    }

    public static function skip(?string $message = null): self
    {
        return new self(ProcessResultEnum::Skip, $message);
    }

    public static function fail(?string $message = null): self
    {
        return new self(ProcessResultEnum::Fail, $message);
    }

    public function isSuccess(): bool
    {
        return $this->result === ProcessResultEnum::Success;
    }

    public function isFail(): bool
    {
        return $this->result === ProcessResultEnum::Fail;
    }
}

Money Value Object

金额值对象

View full implementation →
查看完整实现 →

Usage Examples

使用示例

ProcessResult

ProcessResult

php
// In actions
return ProcessResult::success('Order processed successfully');
return ProcessResult::skip('Order already processed');
return ProcessResult::fail('Payment declined');

// Checking results
if ($result->isSuccess()) {
    // Handle success
}

if ($result->isFail()) {
    // Handle failure
}
php
// 在动作类中
return ProcessResult::success('订单处理成功');
return ProcessResult::skip('订单已处理');
return ProcessResult::fail('支付被拒绝');

// 检查结果
if ($result->isSuccess()) {
    // 处理成功逻辑
}

if ($result->isFail()) {
    // 处理失败逻辑
}

Money

Money

php
// Creating money values
$price = Money::fromDollars(29.99);
$tax = Money::fromDollars(2.40);
$shipping = Money::fromCents(500);  // $5.00

// Operations
$subtotal = $price->add($tax);
$total = $subtotal->add($shipping);

// Multiplication
$bulkPrice = $price->multiply(10);

// Display
echo $total->formatted();  // "37.39"

// Comparison
if ($total->equals($expectedTotal)) {
    // Amounts match
}
php
// 创建金额值
$price = Money::fromDollars(29.99);
$tax = Money::fromDollars(2.40);
$shipping = Money::fromCents(500);  // $5.00

// 运算操作
$subtotal = $price->add($tax);
$total = $subtotal->add($shipping);

// 乘法运算
$bulkPrice = $price->multiply(10);

// 显示
echo $total->formatted();  // "37.39"

// 比较
if ($total->equals($expectedTotal)) {
    // 金额匹配
}

Key Patterns

核心模式

1. Immutability

1. 不可变性

Use
readonly
properties:
php
public readonly int $amount;
public readonly string $currency;
使用
readonly
属性:
php
public readonly int $amount;
public readonly string $currency;

2. Static Factory Methods

2. 静态工厂方法

Named constructors for common scenarios:
php
public static function fromDollars(float $dollars): self
public static function success(?string $message = null): self
针对常见场景的命名构造函数:
php
public static function fromDollars(float $dollars): self
public static function success(?string $message = null): self

3. Private Constructor

3. 私有构造函数

Force use of factory methods:
php
private function __construct(/* ... */) {}
强制使用工厂方法:
php
private function __construct(/* ... */) {}

4. Domain Logic

4. 领域逻辑

Encapsulate domain rules:
php
public function add(Money $other): self
{
    $this->assertSameCurrency($other);
    return new self($this->amount + $other->amount, $this->currency);
}
封装领域规则:
php
public function add(Money $other): self
{
    $this->assertSameCurrency($other);
    return new self($this->amount + $other->amount, $this->currency);
}

5. Return New Instances

5. 返回新实例

Operations return new instances (immutability):
php
public function add(Money $other): self
{
    return new self($this->amount + $other->amount, $this->currency);
}
运算操作返回新实例(保证不可变性):
php
public function add(Money $other): self
{
    return new self($this->amount + $other->amount, $this->currency);
}

Directory Structure

目录结构

app/Values/
├── Money.php
├── ProcessResult.php
├── Coordinate.php
└── EmailAddress.php
app/Values/
├── Money.php
├── ProcessResult.php
├── Coordinate.php
└── EmailAddress.php

Summary

总结

Value objects:
  • Are immutable (use
    readonly
    )
  • Have static factory methods
  • Encapsulate domain logic
  • Return new instances from operations
  • Validate in constructor
Use for domain concepts with behavior, not simple data transfer.
值对象:
  • 是不可变的(使用
    readonly
  • 具备静态工厂方法
  • 封装领域逻辑
  • 运算操作返回新实例
  • 在构造函数中进行验证
适用于带有行为的领域概念,而非简单的数据传输。