Versatile Collections
, (*1)
A collection package that can be extended to implement things such as a Dependency Injection Container,
RecordSet objects for housing database records, a bag of http cookies, or technically any collection of
items that can be looped over and whose items can each be accessed using array-access syntax or object
property syntax., (*2)
You can:
* use one of the provided Collection classes directly in your application(s)
* or include one or more of the provided Collection classes within an existing class in your application and expose features you want (Composition)
* or extend one or more of the the provided Collection classes (Inheritance) and then use those extended classes in your application(s)
* or just implement one or more of the Collection Interfaces and use the corresponding trait (Contract fulfillment), (*3)
This package provides optional strict-typing of collection items and strives for 100 % unit-test coverage., (*4)
, (*5)
Installation
Via composer: (Requires PHP 7.4+ or PHP 8.0+)., (*6)
Switch to the 3.X branch to read the documentation for the 3.X version., (*7)
Switch to the 4.X branch to read the documentation for the 4.X version., (*8)
Switch to the 5.x branch to read the documentation for the 5.x version., (*9)
Switch to the master branch to read the documentation for the latest version., (*10)
composer require rotexsoft/versatile-collections
Basics
If you are simply looking to store items of the same or differing types in a collection you can use simply use the GenericCollection class like so:, (*11)
<?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
You can also make any class in your application behave exactly like \VersatileCollections\GenericCollection
by implementing \VersatileCollections\CollectionInterface and using
\VersatileCollections\CollectionInterfaceImplementationTrait in such classes., (*12)
If you want to enforce strict-typing, the following Collection classes are provided
in this package:, (*13)
-
Arrays Collections: a collection that only stores items that are arrays (i.e. items for which is_array is true)
-
Callables Collections: a collection that only stores items that are callables (i.e. items for which is_callable is true)
-
Objects Collections: a collection that only stores items that are objects (i.e. items for which is_object is true)
-
Non-Array Iterables Collections: a collection that only accepts items that are objects for which \is_iterable returns true. This type of collection does not accept arrays which are also iterables but not objects. Use Arrays Collections to store arrays or you could create a new collection class that accepts all iterables (both arrays & every other type for which is_iterable returns true)
-
Specific Objects Collections: a collection that only stores items that are instances of a specified class or any of its sub-classes
-
Resources Collections: a collection that only stores items that are resources (i.e. items for which is_resource is true)
-
Scalars Collections: a collection that only stores items that are scalars (i.e. items for which is_scalar is true)
-
Numerics Collections: a collection that only stores items that are either floats or integers (i.e. items for which is_int or is_float is true)
-
Floats Collections: a collection that only stores items that are floats (i.e. items for which is_float is true)
-
Ints Collections: a collection that only stores items that are integers (i.e. items for which is_int is true)
-
Strings Collections: a collection that only stores items that are strings (i.e. items for which is_string is true)
To implement a custom collection that only contains objects that are instances of
a specific class (for example \PDO), your custom collection class must adhere to
the following requirements:, (*14)
-
Your custom collection class must implement \VersatileCollections\StrictlyTypedCollectionInterface which currently contains the methods below:, (*15)
-
public function checkType(mixed $item): bool : it must return true if
$item
is of the expected type or false otherwise
-
public function getTypes() : it must return an instance of \VersatileCollections\StringsCollection of strings representing the name(s) of the expected type(s)
-
Your custom collection class should use \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait (which contains implementation of the methods in \VersatileCollections\StrictlyTypedCollectionInterface). If you choose not to use \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait, then you will have to implement all the methods specified in \VersatileCollections\StrictlyTypedCollectionInterface and make sure you call the checkType(mixed $item) method in every method where you add items to or modify items in the collection such as offsetSet($key, $val) and throw an VersatileCollections\Exceptions\InvalidItemException exception whenever checkType(mixed $item) returns false. If you use \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait in your custom collection class but add new methods that also add items to or modify items in the collection you can use the helper method isRightTypeOrThrowInvalidTypeException($item, $calling_functions_name) provided in \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait to validate items (it will automatically throw an exception for you if the item you are validating is of the wrong type; see \VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait::offsetSet($key, $val) for an example of how this helper method should be used)., (*16)
-
You can optionally override StrictlyTypedCollectionInterfaceImplementationTrait::__construct(mixed ...$arr_objs) with a constructor
with the same signature but with the specific type. For example, __construct(\PDO ...$pdo_objs) ensures that only instances of
\PDO can be injected into the constructor via argument unpacking., (*17)
The code example below shows how a custom collection class called PdoCollection,
that only stores items that are instances of \PDO, can be implemented:, (*18)
<?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);
}
}
You can declare your custom typed collection classes as final so that users of your
classes will not be able to extend them and thereby circumvent the type-checking
being enforced at construct time and item addition time., (*19)
NOTE: If you only want to store items that are only instances of a specific class
or its sub-classes in a collection and don't want to have to create a custom collection
class for that purpose, simply use SpecificObjectsCollection, (*20)
Documentation
Issues
- Please submit an issue or a pull request if you find any bugs or better
and more efficient way(s) things could be implemented in this package.
Contributing
- master branch currently contains code for the latest version, which as of March 2024 is 6.x
- Bugfixes for version 5.x should be applied to the 5.x branch.
- Bugfixes for version 4.x should be applied to the 4.X branch.
- Bugfixes for version 3.x should be applied to the 3.X branch.
- Bugfixes for version 2.x should be applied to the 2.X branch.