yomy/datastructures

1.1 2020-12-07 13:47 UTC

This package is auto-updated.

Last update: 2024-09-07 21:59:52 UTC


README

PHP的常见数据结构

Build Status

安装和文档

  • 作为 [Composer] 包 [yomy/datastructures] 提供。

这个库是关于什么的

此库添加了可以用于更好地组织对象的数据结构类

值对象的示例

创建对象

use YomY\DataStructures\ValueObject\ValueObject;
$object = ValueObject::instance(1);

从对象获取值

$value = $object->getValue();

具有相同值的对象将是相同的对象

$object1 = ValueObject::instance(1);
$object2 = ValueObject::instance(1);
//These two are the same objects ($object1 === $object2)

您可以在方法中使用类型提示

public function doSomething(ValueObject $valueObject) {
    $value = $valueObject->getValue();
    ...
}

您可以扩展对象以进行更详细的类型提示

class UserId extends ValueObject {}
class DataId extends ValueObject {}
...
public function doSomething(UserId $userId, DataId $dataId) {
    ...
}

不同类或变量类型的对象是不同的

$object1 = ValueObject::instance('');
$object2 = ValueObject::instance(null);
$object3 = ValueObject::instance(false);
$object4 = ExtendedValueObject::instance('');
$object5 = ExtendedValueObject::instance(null);
$object6 = ExtendedValueObject::instance(false);
//All of the above are different

除了强(===)比较运算符外,您还可以使用 equals() 方法

$object1 = ValueObject::instance(1);
$object2 = ValueObject::instance(1);
$same = $object1->equals($object2); //true

通常,值对象的反序列化是被禁止的,因为这会破坏通过引用比较对象的能力。但是,您可能有一些不关心严格比较的情况,需要反序列化对象。您可以在自定义对象中添加 WeakValueObjectTrait 使用,这将允许反序列化它,并在使用 equals() 方法时通过值而不是引用比较对象

class MyWeakObject extends ValueObject {
    use WeakValueObjectTrait;
}
...
$weakObject1 = MyWeakObject::instance(1);
$serializedWeakObject = serialize($weakObject1);
$weakObject2 = unserialize($serializedWeakObject);
//These two objects are "equal" but not the same
$weakObject1->equals($weakObject2); //true
//On regular value objects this would be false

枚举值对象的示例

创建枚举对象

use YomY\DataStructures\ValueObject\EnumValueObject;
class Category extends EnumValueObject {
    const FIRST = 1;
    const SECOND = 2;
    const THIRD = 3;
}

创建枚举对象

$category = Category::instance(Category::FIRST);

或通过引用键

$category = Category::FIRST();

如果您尝试实例化无效的值,将会出错

$category = Category::instance('missing_value');
$category = Category::MISSING();

正整数值对象的示例

由于值对象通常用作具有整数键的数据库实体的标识符,因此正整数值对象确保了用于此目的的有效键对象

创建对象

use YomY\DataStructures\ValueObject\PositiveIntValueObject;
$object1 = PositiveIntValueObject::instance(1);
$object2 = PositiveIntValueObject::instance('1');
//These two are the same objects ($object1 === $object2)

通常,数据库中的 id 键不能为 0,因此这些对象是无效的

$object = PositiveIntValueObject::instance(0);
$object = PositiveIntValueObject::instance('0');

当然,与基本值对象一样,这些对象旨在在扩展类中使用。

class UserId extends PositiveIntValueObject {}
class DataId extends PositiveIntValueObject {}
$user = UserId::instance(42);
$data = DataId::instance(42);
//these two are not the same

GenericCollection 使用示例

创建集合对象

use YomY\DataStructures\Collection\GenericCollection;
$collection = new GenericCollection();

将对象添加到集合中

$collection->add(1);
$collection->add(2);
$collection->add(3);
$collection->add('string');
$collection->add(true);
$collection->add(false);
$collection->add(null);
$collection->add($anObject);
$collection->add(['an', 'array']);

您也可以使用数组语法添加对象

$collection[] = 1;

对象可以多次添加

$collection->add(1);
$collection->add(1);
$collection->add(1);

集合支持一次性添加值数组的操作

$values = [1, 2, 3];
$collection->addArray($values);

从集合中删除对象 - 删除对象的所有实例

$collection->remove(1);

从集合中获取对象

$objects = $collection->getAll();

注意,您 不能 使用数组语法获取对象

$object = $collection[3]; //This will throw an exception

您也可以遍历集合本身

foreach ($collection as $object) {
    ...
}

计算集合中对象的数量

$count = $collection->count();

验证集合是否为空

$empty = $collection->isEmpty();

验证集合是否包含对象

$contains = $collection->contains(1);

您可以浅拷贝集合

$copy = $collection->copy();

您可以将另一个集合附加到集合中

$collection->append($collection2);
//$collection now has gets items from $collection2 along it's own items

集合支持自定义排序其对象

$values = [9, 8, 7, 6, 5, 4, 3, 2, 1];
$collection = new GenericCollection();
$collection->addArray($values);
$collection->sort(function($object1, $object2) {
    return $object1 > $object2;
});
//Collection will now have an array like
//[1, 2, 3, 4, 5, 6, 7, 8, 9];

集合可以通过过滤来获取包含过滤对象的新的集合

$values = [1, 2, 3, 4, 5, 6, 7, 8, 9];
$collection = new GenericCollection();
$collection->addArray($values);
$filtered = $collection->filter(function($object) {
    return $object > 5;
});
//$filtered contains [6, 7, 8, 9]
//original collection is not affected

集合可以通过回调方法转换为数组。这允许从对象中提取底层数据或进行自定义计算

$values = [1, 2, 3, 4, 5, 6, 7, 8, 9];
$collection = new GenericCollection();
$collection->addArray($values);
$transformed = $collection->transformToArray(function($object) {
    //Here we decide what to return in place of each item
    return new CustomWrapper($object);
});

集合可以转换(附加)到另一个集合中

$values = [1, 2, 3, 4, 5, 6, 7, 8, 9];
$collection = new GenericCollection();
$collection->addArray($values);
$destinationCollection = new GenericCollection();
$destinationCollection->addArray($values);
$collection->transformToCollection($destinationCollection);
//$destinationCollection now has appended items from $collection

ObjectCollection 使用示例

ObjectCollection 是 GenericCollection 的扩展,旨在仅包含特定类的对象。

创建特定类型的 ObjectCollection

$objectCollection = new ObjectCollection(ExampleObject1::class);

GenericCollection 的所有方法几乎以相同的方式工作,只是不允许添加在 Collection 构造函数中传递的确切类型的对象。

$objectCollection = new ObjectCollection(ExampleObject1::class);
$objectCollection->add(new ExampleObject1());

尝试添加错误类型的对象将抛出 InvalidArgumentException

$objectCollection = new ObjectCollection(ExampleObject1::class);
$objectCollection->add(new DifferentObject());
//This will throw an InvalidArgumentException

集合也可以与扩展对象一起工作

class ExtendedExampleObject1 extends ExampleObject1 {}
$objectCollection = new ObjectCollection(ExampleObject1::class);
$objectCollection->add(new ExampleObject1());
$objectCollection->add(new ExtendedExampleObject1());

ObjectCollection 的主要目的是拥有一个自定义命名的集合

class User {...}
class UserCollection extends ObjectCollection {
    public function __construct() {
        parent::__construct(User::class);
    }
}

拥有此类集合允许在代码中进行类型提示,并且我们确信该集合只包含特定类型的对象。

function someMethod(UserCollection $userCollection) {
    foreach ($userCollection as $user) {
        //Here we can use individual users from collection
    }
}

...

$userCollection = new UserCollection();
$userCollection->add($user1);
$userCollection->add($user2);
$userCollection->add($user3);

someMethod($userCollection);

在某些情况下,我们需要尝试从一个未知对象数组中填充一个集合。tryAddArray() 方法将允许安全地尝试添加所有正确类型的对象,并提供一个无法添加的对象数组。

$failed = $objectCollection->tryAddArray($objects);
//the $failed array will contain objects that were not added to collection

KeyValueCollection 使用示例

KeyValueCollection 是一个旨在包含键=>值对的集合。内部,此集合持有 Pair 类型的对象,但目的是不直接使用这些 Pair 对象,而是通过在集合对象上直接设置键和值。

$keyValueCollection = new KeyValueCollection();

应通过 put() 和 get() 方法使用 KeyValueCollection。

$keyValueCollection->put('key', 'value');
$value = $keyValueCollection->get('key');
//$value will contain the string 'value'

使用 KeyValueCollection 时,您也可以使用数组语法。

$keyValueCollection['key'] = 'value';
$value = $keyValueCollection['key'];
//$value will contain the string 'value'

KeyValueCollection 具有唯一的键。这意味着将某物放在已存在的键上将会覆盖集合中的值。

$keyValueCollection->put('key', 'value');
$keyValueCollection->put('key', 'newValue');
$value = $keyValueCollection->get('key');
//$value will contain the string 'newValue'

现在,您可能认为这仅仅是模拟关联数组,那么为什么还要使用它呢?

KeyValueCollection 的强大之处在于它可以持有对象作为键,因此您可以有

class UserId {...} //A Value Object class
class User {...} //A user details object class

class UserCollection extends KeyValueCollection {
    public function __construct() {
        parent::__construct(UserId::class, User::class);
    }
}

...

//Just for example. These would probably have been built and used inside your application
$userId = new UserId();
$user = new User();

...

$userCollection = new UserCollection();
$userCollection->put($userId, $user);
$user = $userCollection->get($userId);