承接 funeralzone/valueobjects 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

funeralzone/valueobjects

Composer 安装命令:

composer require funeralzone/valueobjects

包简介

A PHP 7.1 value objects helper library.

README 文档

README

Build Status Version

Requirements

Requires PHP >= 7.1

Installation

Through Composer, obviously:

composer require funeralzone/valueobjects

Extensions

This library only deals with fundamental values (scalars). We've also released an extension library which provides a starting point for more complex values.

Our approach

We've written up our philosophy to PHP value objects in our A better way of writing value objects in PHP article.

Single value object

If your VO encapsulates a single value, it's most likely a scalar. We've provided some traits to deal with scalars under:

src/Scalars

Let's say you have a domain value called 'User Email'. You'd create a class which implements the ValueObject interface:

final class UserEmail implements ValueObject {
...

You now need to implement the interface. But because an email can essentially be considered a special kind of string (in this simple case) the StringTrait helper trait can implement most of the interface for you:

final class UserEmail implements ValueObject {

    use StringTrait;
...

In our case, a user's email has other domain logic that we can encapsulate in our VO. User emails have to be a valid email:

...
    public function __construct(string $string)
    {
        Assert::that($string)->email();
        $this->string = $string;
    }
...

You can see an example of how to implement single value objects in the examples directory.

Enums

Enums can be defined easily through use of the EnumTrait. Then, the enum values are simply listed as constants on the class.

final class Fastening implements ValueObject
{
    use EnumTrait;
    
    public const BUTTON = 0;
    public const CLIP = 1;
    public const PIN = 2;
    public const ZIP = 3;
}

When dealing with value object serialisation, the constant names are used. They are case-sensitive. So:

$fastening = Fastening::fromNative('BUTTON');
$fastening->toNative(); // Equals to string: 'BUTTON'

In code, the trait utilises magic methods to create objects based on constant name like so:

$fastening = Fastening::ZIP();
$fastening->toNative(); // Equals 'ZIP'

If your IDE supports code completion and you'd like to use named methods to create enums you can add the following PHPDoc block to your enum class:

/**
 * @method static Fastening BUTTON()
 * @method static Fastening CLIP()
 * @method static Fastening PIN()
 * @method static Fastening ZIP()
 */
final class Fastening implements ValueObject

Composite value objects

A composite value object is a more complex value which is made from other values.

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;
    }
...

A Location is made up of two VOs (latitude, longitude). We've provided a CompositeTrait to easily implement most of the ValueObject interface automatically. It handles toNative serialistation by using reflection to return an array of all the class properties.

The CompositeTrait does not implement fromNative. We leave the construction of your object up to you.

...
    public static function fromNative($native)
    {
        return new static(
            Latitude::fromNative($native['latitude']),
            Longitude::fromNative($native['longitude'])
        );
    }
...

You can see an example of how to implement composite objects in the examples directory.

Nulls, NonNulls and Nullables

This package allows you to deal with nullable value objects.

First create a type of value object.

interface PhoneNumber extends ValueObject
{
}

Implement a non-null version of the value object.

final class NonNullPhoneNumber implements PhoneNumber
{
    use StringTrait;
}

Implement a null version of the value object.

final class NullPhoneNumber implements PhoneNumber
{
    use NullTrait;
}

Implement a nullable version of the value object.

final class NullablePhoneNumber extends Nullable implements PhoneNumber
{
    protected static function nonNullImplementation(): string
    {
        return NonNullPhoneNumber::class;
    }
    
    protected static function nullImplementation(): string
    {
        return NullPhoneNumber::class;
    }
}

This 'nullable' handles automatic creation of either a null or a non-null version of the interface based on the native input. For example:

$phoneNumber = NullablePhoneNumber::fromNative(null);

The $phoneNumber above will automatically use the NullPhoneNumber implementation specified above.

Or:

$phoneNumber = NullablePhoneNumber::fromNative('+44 73715525763');

The $phoneNumber above will automatically use the NonNullPhoneNumber implementation specified above.

Sets of value objects

A set of value objects should implement the Set interface. It's just an extension of the ValueObject interface with a few simple additions.

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 Add values from another set to the current set.
  • remove Remove all the values contained in another set from the current set.
  • contains Returns true if the value exists in the current set.
  • toArray Returns a simple PHP array containing all of the value objects.

The other interfaces that the Set interface extends from (\IteratorAggregate, \ArrayAccess, \Countable) are for accessing the set object as though it was an array.

Non-null sets

The library provides a default implementation of the interface.

final class SetOfLocations extends NonNullSet implements Set
{
    protected function typeToEnforce(): string
    {
        return Location::class;
    }

    public static function valuesShouldBeUnique(): bool
    {
        return true;
    }
}

There are two abstract methods that need to be implemented.

  • typeToEnforce should return a string of the class name of the value object that you want to make a set of.
  • valuesShouldBeUnique should return a boolean representing whether you want to force the set to be unique.

If the set is set to unique, if duplicate values are added to the set (at instantiation or through the add method) the duplicates are filtered out.

Null and nullable sets

Just like standard value objects there are some constructs to help with creating nullable and null sets. See the Nulls, NonNulls and Nullables section for more information.

  • NullableSet The set equivalent of Nullable.
  • NullSetTrait The set equivalent of the NullTrait.

Usage of sets

Iteration, access and counting

// 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

Merges another set.

$set = new SetOfLocations([$one, $two]);
$anotherSet = new SetOfLocations([$three]);
$mergedSet = $set->add($anotherSet);
count($mergedSet) // Equals: 3

remove

Removes values from a set by using another set as reference values.

$set = new SetOfLocations([$one, $two, $three]);
$anotherSet = new SetOfLocations([$one]);
$remove = $set->remove($anotherSet);
count($remove) // Equals: 2

contains

Checks whether a set contains a particular value object.

$set = new SetOfLocations([$one, $two, $three]);
$one = new Location(0);
$check = $set->contains($one);

funeralzone/valueobjects 适用场景与选型建议

funeralzone/valueobjects 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 699.49k 次下载、GitHub Stars 达 66, 最近一次更新时间为 2017 年 12 月 08 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 funeralzone/valueobjects 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 funeralzone/valueobjects 我们能提供哪些服务?
定制开发 / 二次开发

基于 funeralzone/valueobjects 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 699.49k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 66
  • 点击次数: 20
  • 依赖项目数: 25
  • 推荐数: 0

GitHub 信息

  • Stars: 66
  • Watchers: 5
  • Forks: 7
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2017-12-08