rotexsoft / versatile-collections
一个可扩展的集合包,可用于实现依赖注入容器、用于存储数据库记录的RecordSet对象、http cookies的集合,或技术上任何可以循环遍历且其元素可以使用数组访问语法访问的项集合
Requires
- php: >=8.1.0
Requires (Dev)
- php-coveralls/php-coveralls: ^2.0
- phpunit/phpunit: ^10.0
- rector/rector: ^1.0.0
- vimeo/psalm: ^5.4.0
README
一个可扩展的集合包,可以用来实现依赖注入容器、存放数据库记录的RecordSet对象、http cookie集合,或者技术上任何可以循环遍历且其元素可以使用数组访问语法或对象属性语法访问的元素集合。
您可以使用以下方法之一:
- 直接在您的应用程序中使用提供的集合类
- 或在您的应用程序中现有的类中包含一个或多个提供的集合类,并公开您想要的特性(组合)
- 或扩展一个或多个提供的集合类(继承)然后在使用这些扩展类在您的应用程序中
- 或者只需实现一个或多个集合接口并使用相应的特性(合同履行)
该包提供集合元素的严格类型可选,并力求实现100%的单元测试覆盖率。
安装
通过composer安装:(需要PHP 7.4+或PHP 8.0+)。
切换到3.X分支以阅读3.X版本的文档。
切换到4.X分支以阅读4.X版本的文档。
切换到5.x分支以阅读5.x版本的文档。
切换到master分支以阅读最新版本的文档。
composer require rotexsoft/versatile-collections
基本内容
如果您只是想在一个集合中存储相同或不同类型的元素,您可以直接使用如下所示的GenericCollection类
<?php use \VersatileCollections\GenericCollection; // items to be stored in your collection $item1 = ['yabadoo']; // an array $item2 = function(){ echo 'Hello World!'; }; // a callable $item3 = 777.888; // a float $item4 = 777; // an int $item5 = new \stdClass(); // an object $item6 = new \ArrayObject([]); // another object $item7 = tmpfile(); // a resource $item8 = true; // a boolean $item9 = "true"; // a string // Technique 1: pass the items to the constructor of the collection class $collection = new \VersatileCollections\GenericCollection( $item1, $item2, $item3, $item4, $item5, $item6, $item7, $item8, $item9 ); // Technique 2: pass the items in an array using argument unpacking // to the constructor of the collection class $collection = new GenericCollection( ...[$item1, $item2, $item3, $item4, $item5, $item6, $item7, $item8, $item9] ); // Technique 3: pass the items in an iterable (such as an array) to the static makeNew helper method // available in all collection classes $collection = GenericCollection::makeNew( [$item1, $item2, $item3, $item4, $item5, $item6, $item7, $item8, $item9] ); // Technique 4: create an empty collection object and subsequently add each // item to the collection via array assignment syntax or object // property assignment syntax or using the appendItem($item), // prependItem($item, $key=null), push($item) or put($key, $value) // methods $collection = new GenericCollection(); // empty collection // OR $collection = GenericCollection::makeNew(); // empty collection $collection[] = $item1; // array assignment syntax without key // the item is automatically assigned // the next available integer key. In // this case 0 $collection[] = $item2; // array assignment syntax without key // the next available integer key in this // case is 1 $collection['some_key'] = $item3; // array assignment syntax with specified key `some_key` $collection->some_key = $item4; // object property assignment syntax with specified property // `some_key`. This will update $collection['some_key'] // changing its value from $item3 to $item4 $collection->appendItem($item3) // same effect as: ->appendItem($item5); // $collection[] = $item3; // $collection[] = $item5; // Adds an item to the end of the collection // You can chain the method calls $collection->prependItem($item6, 'new_key'); // adds an item with the optional // specified key to the front of // collection. // You can chain the method calls $collection->push($item7); // same effect as: // $collection[] = $item7; // Adds an item to the end of the collection // You can chain the method calls $collection->put('eight_item', $item8) // same effect as: ->put('ninth_item', $item9); // $collection['eight_item'] = $item8; // $collection['ninth_item'] = $item9; // Adds an item with the specified key to // the collection. If the specified key // already exists in the collection the // item previously associated with the // key is overwritten with the new item. // You can chain the method calls
您也可以通过实现\VersatileCollections\CollectionInterface并在这些类中使用\VersatileCollections\CollectionInterfaceImplementationTrait,使您应用程序中的任何类表现得像\VersatileCollections\GenericCollection。
如果您想强制执行严格类型,该包提供了以下集合类
- 数组集合:一个只存储数组(即对于is_array返回true的项)的集合
- 可调用集合:一个只存储可调用项(即对于is_callable返回true的项)的集合
- 对象集合:一个只存储对象(即对于is_object返回true的项)的集合
- 资源集合:一个只存储资源(即对于is_resource返回true的项)的集合
- 标量集合:一个只存储标量(即对于is_scalar返回true的项)的集合
要实现一个只包含特定类(例如 \PDO)实例的定制集合,您的定制集合类必须遵循以下要求
-
您的定制集合类必须实现 \VersatileCollections\StrictlyTypedCollectionInterface,它目前包含以下方法
- public function checkType(mixed $item): bool : 如果
$item
是期望的类型则必须返回true,否则返回false - public function getTypes() : 必须返回一个代表期望类型名称的字符串实例的 \VersatileCollections\StringsCollection
- public function checkType(mixed $item): bool : 如果
-
您的定制集合类应使用 \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait(它包含 \VersatileCollections\StrictlyTypedCollectionInterface 方法的实现)。如果您选择不使用 \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait,那么您将必须实现 \VersatileCollections\StrictlyTypedCollectionInterface 中指定的所有方法,并确保在添加或修改集合中的项的每个方法中调用 checkType(mixed $item) 方法,如 offsetSet($key, $val),并在 checkType(mixed $item) 返回false时抛出 VersatileCollections\Exceptions\InvalidItemException 异常。如果您在您的定制集合类中使用 \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait 但添加了新方法,这些方法也添加或修改集合中的项,您可以使用 \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait 中提供的辅助方法 isRightTypeOrThrowInvalidTypeException($item, $calling_functions_name) 来验证项(如果验证的项类型不正确,它将自动抛出异常;请参阅 \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait::offsetSet($key, $val) 以了解如何使用此辅助方法)。
-
您可以选择覆盖 StrictlyTypedCollectionInterfaceImplementationTrait::__construct(mixed ...$arr_objs) 以具有相同签名的构造函数,但具有特定类型。例如,__construct(\PDO ...$pdo_objs) 确保只能通过参数解包将 \PDO 实例注入构造函数。
下面的代码示例显示了如何实现一个名为 PdoCollection 的自定义集合类,该类只存储 \PDO 的实例
<?php use \VersatileCollections\StrictlyTypedCollectionInterface; class PdoCollection implements StrictlyTypedCollectionInterface { //1. Implement interface use \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait; //2. Use trait public function __construct(\PDO ...$pdo_objs) { //3. Optionally override the constructor with a type // specific one $this->versatile_collections_items = $pdo_objs; } /** * * @return bool true if $item is of the expected type, else false * */ public function checkType(mixed $item): bool { //4. implement interface methods not implemented in trait above return ($item instanceof \PDO); } /** * * @return string|array a string or array of strings of type name(s) * for items acceptable in instances of this * collection class * */ public function getTypes(): \VersatileCollections\StringsCollection { //4. implement interface methods not implemented in trait above return new \VersatileCollections\StringsCollection(\PDO::class); } }
您可以将您的自定义类型集合类声明为 final,这样用户就不能扩展它们,从而绕过构造时和项添加时的类型检查。
注意:如果您只想在集合中存储特定类或其子类的实例,而不想为此创建自定义集合类,只需使用 SpecificObjectsCollection
文档
-
严格类型集合
-
如果在文档中发现问题,请提交问题或拉取请求。
问题
- 如果在包中找到错误或更好的、更高效的方法来实现某些功能,请提交问题或拉取请求。
贡献
- master 分支目前包含最新版本的代码,截至 2024 年 3 月为 6.x 版本
- 5.x 版本的错误修复应应用于 5.x 分支。
- 4.x 版本的错误修复应应用于 4.X 分支。
- 3.x 版本的错误修复应应用于 3.X 分支。
- 2.x 版本的错误修复应应用于 2.X 分支。