本文目录导读:

在 Laravel 中使用 PHP 值对象(Value Object),以下是一些最佳实践和示例:
基础值对象实现
<?php
namespace App\ValueObjects;
use InvalidArgumentException;
class Email
{
private string $value;
public function __construct(string $email)
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException("Invalid email address: {$email}");
}
$this->value = $email;
}
public function value(): string
{
return $this->value;
}
public function equals(Email $other): bool
{
return $this->value === $other->value;
}
public function __toString(): string
{
return $this->value;
}
}
在 Eloquent 模型中使用
使用 Casts 特性(Laravel 7+)
<?php
namespace App\Models;
use App\ValueObjects\Email;
use App\ValueObjects\Money;
use App\ValueObjects\Address;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $casts = [
'email' => Email::class,
'wallet_balance' => Money::class,
'address' => Address::class,
];
// 自定义 cast 方法
protected function asEmail(string $value): Email
{
return new Email($value);
}
}
自定义 Cast 类
<?php
namespace App\Casts;
use App\ValueObjects\Email;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class EmailCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes): ?Email
{
if ($value === null) {
return null;
}
return new Email($value);
}
public function set($model, string $key, $value, array $attributes): ?string
{
if ($value === null) {
return null;
}
if ($value instanceof Email) {
return $value->value();
}
return (new Email($value))->value();
}
}
// 在模型中使用
class User extends Model
{
protected $casts = [
'email' => \App\Casts\EmailCast::class,
];
}
复杂值对象示例
<?php
namespace App\ValueObjects;
class Money
{
private int $amount;
private string $currency;
public function __construct(int $amount, string $currency = 'USD')
{
if ($amount < 0) {
throw new \InvalidArgumentException('Amount cannot be negative');
}
$this->amount = $amount;
$this->currency = strtoupper($currency);
}
public function add(Money $other): self
{
if ($this->currency !== $other->currency) {
throw new \InvalidArgumentException('Cannot add different currencies');
}
return new self($this->amount + $other->amount, $this->currency);
}
public function format(): string
{
return number_format($this->amount / 100, 2) . ' ' . $this->currency;
}
public function getAmount(): int
{
return $this->amount;
}
public function getCurrency(): string
{
return $this->currency;
}
public function equals(Money $other): bool
{
return $this->amount === $other->amount && $this->currency === $other->currency;
}
}
// 在模型中使用
class Order extends Model
{
public function total(): Money
{
return new Money(
$this->items->sum(fn($item) => $item->price->getAmount()),
'USD'
);
}
}
在 Form Request 中使用
<?php
namespace App\Http\Requests;
use App\ValueObjects\Email;
use Illuminate\Foundation\Http\FormRequest;
class CreateUserRequest extends FormRequest
{
public function rules(): array
{
return [
'email' => 'required|email|unique:users',
'name' => 'required|string|max:255',
];
}
public function toEmail(): Email
{
return new Email($this->input('email'));
}
}
// 在控制器中使用
public function store(CreateUserRequest $request)
{
$email = $request->toEmail();
User::create([
'email' => $email->value(),
'name' => $request->input('name'),
]);
}
在 Repository 中使用
<?php
namespace App\Repositories;
use App\Models\User;
use App\ValueObjects\Email;
use App\ValueObjects\UserId;
class UserRepository
{
public function findByEmail(Email $email): ?User
{
return User::where('email', $email->value())->first();
}
public function findById(UserId $id): ?User
{
return User::find($id->value());
}
}
使用 Trait 简化操作
<?php
namespace App\Traits;
use App\ValueObjects\Email;
use App\ValueObjects\Money;
trait HasValueObjects
{
public function getEmailAttribute($value): ?Email
{
return $value ? new Email($value) : null;
}
public function setEmailAttribute($value): void
{
$this->attributes['email'] = $value instanceof Email
? $value->value()
: (new Email($value))->value();
}
public function getWalletBalanceAttribute($value): ?Money
{
return $value ? new Money($value, 'USD') : null;
}
public function setWalletBalanceAttribute($value): void
{
$this->attributes['wallet_balance'] = $value instanceof Money
? $value->getAmount()
: $value;
}
}
// 在模型中使用
class User extends Model
{
use HasValueObjects;
}
验证规则集成
<?php
namespace App\Rules;
use App\ValueObjects\Email;
use Illuminate\Contracts\Validation\Rule;
class ValidEmailValueObject implements Rule
{
public function passes($attribute, $value): bool
{
try {
new Email($value);
return true;
} catch (\Exception $e) {
return false;
}
}
public function message(): string
{
return 'The :attribute is not a valid email address.';
}
}
// 在表单请求中使用
class UpdateUserRequest extends FormRequest
{
public function rules(): array
{
return [
'email' => ['required', new ValidEmailValueObject()],
];
}
}
主要优点:
- 类型安全 - 确保数据始终有效
- 自文档化 - 代码意图清晰
- 可测试性 - 易于单元测试
- 封装逻辑 - 业务规则集中在值对象中
- 不变性 - 减少意外修改
最佳实践:
- 保持值对象不可变
- 实现
equals()方法用于比较 - 考虑使用
__toString()方法 - 在构造函数中进行验证
- 使用命名构造函数提高可读性
这种模式可以显著提高 Laravel 应用的代码质量和可维护性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播