albanh / valueobjects
PHP 7.1的值对象辅助库。
Requires
- php: ^7.1.0
- beberlei/assert: ^2.7 || ^3.1
- chrisharrison/php-array-of: ^1.0
Requires (Dev)
- mockery/mockery: ^1.0
- phpunit/phpunit: ^6.2
- squizlabs/php_codesniffer: ^3.1
- dev-master
- 0.4.5
- 0.4.4
- 0.4.3
- 0.4.2
- 0.4
- 0.3.4
- 0.3.3
- 0.3.2
- 0.3.1
- 0.3.0
- 0.2.1
- 0.2.0
- 0.1.0
- 0.0.3
- 0.0.2
- 0.0.1
- 0.0.0
- dev-feature/boolean-method-helpers
- dev-feature/ability-to-get-only-non-null-values-from-a-set
- dev-feature/boolean-helpers
- dev-feature/create-null-nullable
- dev-feature/null-composites
- dev-fix/array-casting
- dev-feature/set-to-array
- dev-feature/set-functionality
- dev-feature/nullable-sets
- dev-fix/mockery-tear-down
This package is auto-updated.
Last update: 2024-09-06 04:44:42 UTC
README
需求
需要PHP 7.1
安装
显然,通过Composer安装
composer require funeralzone/valueobjects
扩展
这个库只处理基本值(标量)。我们还发布了一个扩展库,它为更复杂的值提供了一个起点。
我们的方法
我们在PHP中编写更好的值对象方法一文中阐述了我们关于PHP值对象的哲学。
单个值对象
如果你的VO封装了一个单个值,那么它很可能是标量。我们在下面提供了处理标量的某些特质
src/Scalars
假设你有一个名为'User Email'的领域值。你需要创建一个实现了ValueObject
接口的类
final class UserEmail implements ValueObject { ...
现在你需要实现该接口。但是因为电子邮件可以基本上被视为字符串的特殊类型(在这个简单案例中),所以StringTrait
辅助特质可以为你实现大部分接口
final class UserEmail implements ValueObject { use StringTrait; ...
在我们的案例中,用户的电子邮件有其他领域逻辑,我们可以将其封装在我们的VO中。用户电子邮件必须是有效的电子邮件
... public function __construct(string $string) { Assert::that($string)->email(); $this->string = $string; } ...
你可以在示例目录中看到如何实现单个值对象的示例。
枚举
可以通过使用EnumTrait
轻松定义枚举。然后,枚举值简单地作为类上的常量列出。
final class Fastening implements ValueObject { use EnumTrait; public const BUTTON = 0; public const CLIP = 1; public const PIN = 2; public const ZIP = 3; }
处理值对象序列化时,使用常量名称。它们是区分大小写的。所以
$fastening = Fastening::fromNative('BUTTON'); $fastening->toNative(); // Equals to string: 'BUTTON'
在代码中,特质使用魔术方法根据常量名称创建对象,如下所示
$fastening = Fastening::ZIP(); $fastening->toNative(); // Equals 'ZIP'
如果你的IDE支持代码补全并且你想使用命名方法创建枚举,你可以在你的枚举类中添加以下PHPDoc块
/** * @method static Fastening BUTTON() * @method static Fastening CLIP() * @method static Fastening PIN() * @method static Fastening ZIP() */ final class Fastening implements ValueObject
组合值对象
组合值对象是一个更复杂的值,由其他值组成。
final class Location implements ValueObject { use CompositeTrait; private $latitude; private $longitude; public function __construct(Latitude $latitude, Longitude $longitude) { $this->latitude = $latitude; $this->longitude = $longitude; } public function getLatitude(): Latitude { return $this->latitude; } public function getLongitude(): Longitude { return $this->longitude; } ...
Location
由两个VO(纬度、经度)组成。我们提供了一个CompositeTrait
,可以自动轻松实现大部分ValueObject
接口。它通过反射返回所有类属性数组来处理toNative
序列化。
CompositeTrait
不实现fromNative
。我们将对象的构建留给你。
... public static function fromNative($native) { return new static( Latitude::fromNative($native['latitude']), Longitude::fromNative($native['longitude']) ); } ...
你可以在示例目录中看到如何实现组合对象的示例。
Nulls,NonNulls和Nullables
此包允许您处理可空值对象。
首先创建一个值对象类型。
interface PhoneNumber extends ValueObject { }
实现值对象的非空版本。
final class NonNullPhoneNumber implements PhoneNumber { use StringTrait; }
实现值对象的空版本。
final class NullPhoneNumber implements PhoneNumber { use NullTrait; }
实现值对象的可空版本。
final class NullablePhoneNumber extends Nullable implements PhoneNumber { protected static function nonNullImplementation(): string { return NonNullPhoneNumber::class; } protected static function nullImplementation(): string { return NullPhoneNumber::class; } }
此'可空'根据原生输入自动创建接口的空或非空版本。例如
$phoneNumber = NullablePhoneNumber::fromNative(null);
上面的$phoneNumber
将自动使用上面指定的NullPhoneNumber
实现。
或
$phoneNumber = NullablePhoneNumber::fromNative('+44 73715525763');
上面的$phoneNumber
将自动使用上面指定的NonNullPhoneNumber
实现。
值对象集合
值对象集合应实现Set
接口。它只是ValueObject
接口的简单扩展,添加了一些简单功能。
interface Set extends ValueObject, \IteratorAggregate, \ArrayAccess, \Countable { public function add($set); public function remove($set); public function contains(ValueObject $value): bool; public function toArray(): array; }
add
将来自另一个集合的值添加到当前集合。remove
从当前集合中删除包含在另一个集合中的所有值。contains
如果当前集合中存在该值,则返回true
。toArray
返回包含所有值对象的简单PHP数组。
Set
接口扩展的其他接口(\IteratorAggregate
、\ArrayAccess
、\Countable
)用于将集合对象作为数组访问。
非空集合
库提供了接口的默认实现。
final class SetOfLocations extends NonNullSet implements Set { protected function typeToEnforce(): string { return Location::class; } public static function valuesShouldBeUnique(): bool { return true; } }
需要实现两个抽象方法。
typeToEnforce
应返回一个字符串,表示您想要将其制作成集合的值对象的类名。valuesShouldBeUnique
应返回一个布尔值,表示您是否想强制集合为唯一。
如果设置集合为唯一,则在添加重复值到集合(在实例化或通过 add
方法)时,重复值将被过滤掉。
空值和可空集合
与标准值对象类似,有一些结构可以帮助创建可空和空集合。有关更多信息,请参阅“空值、非空值和可空值”部分。
NullableSet
是Nullable
的集合等价物。NullSetTrait
是NullTrait
的集合等价物。
集合的使用
迭代、访问和计数
// Iteration $set = new SetOfLocations([$one, $two]); foreach($set as $value) { // TODO: Do something with each value object } // Access $one = $set[0]; $two = $set[1]; //Counting $count = count($set); // Returns 2
add
合并另一个集合。
$set = new SetOfLocations([$one, $two]); $anotherSet = new SetOfLocations([$three]); $mergedSet = $set->add($anotherSet); count($mergedSet) // Equals: 3
remove
通过使用另一个集合作为参考值从集合中删除值。
$set = new SetOfLocations([$one, $two, $three]); $anotherSet = new SetOfLocations([$one]); $remove = $set->remove($anotherSet); count($remove) // Equals: 2
contains
检查集合是否包含特定的值对象。
$set = new SetOfLocations([$one, $two, $three]); $one = new Location(0); $check = $set->contains($one);