ramsey/collection

repository·main·Indexed 22 days ago

https://github.com/ramsey/collection

A PHP library for representing and manipulating collections, inspired by the Java Collections Framework. It provides robust tools for type-safe collections, including implementations for Queue, DoubleEndedQueue, Set, TypedMap, and NamedParameterMap.

Tokens
4.1K
Snippets
13
Records
20
Agent score
77%

What's inside ramsey/collection

  1. Extend TypedMap or AbstractTypedMap for custom implementations

    main

    While you can use TypedMap directly, it is often preferable to subclass AbstractTypedMap to create a specialized typed map implementation. This allows you to hardcode the key and value types within the class definition.

    There are two ways to extend the functionality:

    1. Subclassing AbstractTypedMap: Best for creating a clean, custom implementation where you define getKeyType() and getValueType() methods.
    2. Subclassing TypedMap: Best for creating a specialized version of the existing TypedMap by overriding the constructor to pass specific types to the parent.
    // Option 1: Subclassing AbstractTypedMap
    class FooTypedMap extends AbstractTypedMap
    {
        public function getKeyType()
        {
            return 'int';
        }
    
        public function getValueType()
        {
             return Foo::class;
        }
    }
    
    // Option 2: Subclassing TypedMap
    class FooTypedMap extends TypedMap
    {
        public function __construct(array $data = [])
        {
            parent::__construct('int', Foo::class, $data);
        }
    }
  2. Create custom typed collections by subclassing AbstractCollection

    main

    For better type safety and the ability to perform type-checking on the collection object itself (e.g., using instanceof), it is recommended to subclass Ramsey\Collection\AbstractCollection instead of using the base Collection class. When subclassing, you must implement the getType() method to return the string name of the class type the collection holds.

    namespace My\Foo;
    
    class FooCollection extends \Ramsey\Collection\AbstractCollection
    {
        public function getType(): string
        {
            return 'My\\Foo';
        }
    }
    
    // Usage:
    $fooCollection = new \My\Foo\FooCollection();
    $fooCollection->add(new \My\Foo());
    
    if ($fooCollection instanceof \My\Foo\FooCollection) {
        // This collection is guaranteed to be a collection of My\Foo objects
    }
  3. Use the Collection class for quick typed collections

    main

    The Ramsey\Collection\Collection class is a direct implementation of CollectionInterface used to represent a group of objects of a specific type. You can instantiate it by passing the fully qualified class name of the objects it should contain as the first argument to the constructor. This is useful for quick implementations where you don't want to create a custom subclass.

    $collection = new \Ramsey\Collection\Collection('My\\Foo');
    $collection->add(new \My\Foo());
    $collection->add(new \My\Foo());
    
    foreach ($collection as $foo) {
        // $foo is an instance of My\Foo
    }
  4. Use NamedParameterMap to manage typed named parameters

    main

    The NamedParameterMap class is a specialized map implementation designed to hold values associated with a predefined set of named keys. It enforces two constraints:

    1. Key Restriction: You can only set values for keys that were explicitly defined in the $namedParameters array during construction. Attempting to set an unconfigured key throws a Ramsey\Collection\Exception\InvalidArgumentException.
    2. Type Enforcement: If a type is specified for a named parameter, the map validates that any value assigned to that key matches the required type. If validation fails, it throws a Ramsey\Collection\Exception\InvalidArgumentException.

    When constructing the map, the $namedParameters array can be defined in two ways:

    • Keyed by name: ['param_name' => 'type'] (e.g., ['id' => 'int']).
    • Indexed list: ['param_name_1', 'param_name_2'] (where types default to mixed).
    use Ramsey\Collection\Map\NamedParameterMap;
    
    // Define parameters: 'id' must be an int, 'name' must be a string, 'meta' is mixed
    $config = [
        'id' => 'int',
        'name' => 'string',
        'meta'
    ];
    
    $map = new NamedParameterMap($config, ['id' => 1, 'name' => 'John Doe']);
    
    // Valid operations
    $map['id'] = 2; 
    $map['meta'] = ['foo' => 'bar'];
    
    // This will throw InvalidArgumentException (unconfigured key)
    // $map['unknown'] = 'value';
    
    // This will throw InvalidArgumentException (type mismatch)
    // $map['id'] = 'not-an-int';
    
    // Retrieve the configuration
    $params = $map->getNamedParameters();
  5. Use DoubleEndedQueue for FIFO and LIFO operations

    main

    The DoubleEndedQueue class is a concrete implementation of DoubleEndedQueueInterface that allows you to add or remove elements from both the front (head) and the back (tail) of the collection. It extends the base Queue class and enforces type safety based on a provided $queueType.

    Key Operations

    Adding Elements

    • addFirst(mixed $element): bool: Adds an element to the front. Throws InvalidArgumentException if the type is incorrect.
    • addLast(mixed $element): bool: Adds an element to the back (alias for add()).
    • offerFirst(mixed $element): bool: Attempts to add to the front. Returns false instead of throwing an exception if the type is incorrect.
    • offerLast(mixed $element): bool: Attempts to add to the back. Returns false if the type is incorrect.

    Removing Elements

    • removeFirst(): mixed: Removes and returns the first element. Throws NoSuchElementException if empty.
    • removeLast(): mixed: Removes and returns the last element. Throws NoSuchElementException if empty.
    • pollFirst(): mixed|null: Returns the first element or null if the queue is empty.
    • pollLast(): mixed|null: Returns the last element or null if the queue is empty.

    Inspecting Elements

    • firstElement(): mixed: Returns the first element. Throws NoSuchElementException if empty.
    • lastElement(): mixed: Returns the last element. Throws NoSuchElementException if empty.
    • peekFirst(): mixed|null: Returns the first element or null if empty.
    • peekLast(): mixed|null: Returns the last element or null if empty.
    use Ramsey\Collection\DoubleEndedQueue;
    
    // Initialize with a type (e.g., 'string') and optional initial data
    $queue = new DoubleEndedQueue('string', ['a', 'b']);
    
    $queue->addFirst('start'); // ['start', 'a', 'b']
    $queue->addLast('end');   // ['start', 'a', 'b', 'end']
    
    $first = $queue->removeFirst(); // 'start'
    $last = $queue->removeLast();    // 'end'
  6. Use the Set class for unique collections

    main

    The Set class provides a collection that ensures all elements are unique. When adding an element, the add() method returns true if the element was successfully added and false if the element already exists in the set.

    Warning on Mutable Objects: If you use mutable objects as set elements, changing the object's value in a way that affects equality comparisons while it is in the set can lead to undefined behavior. Use caution when storing objects that can change state.

    $foo = new \My\Foo();
    $set = new Set(\My\Foo::class);
    
    $set->add($foo); // returns TRUE, the element doesn't exist
    $set->add($foo); // returns FALSE, the element already exists
    
    $bar = new \My\Foo();
    $set->add($bar); // returns TRUE, $bar !== $foo
  7. Use TypedMap to enforce type constraints on keys and values

    main

    The TypedMap class is a map implementation where both keys and values must adhere to specific types. You instantiate it by providing the key type (as a string, e.g., 'string' or 'int') and the value type (as a string, e.g., a class name like Foo::class).

    When attempting to assign a key or value that does not match the defined types, the map will throw an exception. You can also initialize the map with an existing array of data.

    Key behaviors:

    • Keys must be unique.
    • Values can be repeated but must be associated with different keys.
    • The map is iterable via foreach.
    $map = new TypedMap('string', Foo::class);
    $map['x'] = new Foo();
    
    foreach ($map as $key => $value) {
        // $key is a string, $value is an instance of Foo
    }
    
    // Initialize with data
    $map = new TypedMap('string', Foo::class, [
        new Foo(), 
        new Foo()
    ]);
  8. Use the Queue class for sequential data processing

    main

    The Ramsey\Collection\Queue class is a basic implementation of QueueInterface that extends AbstractArray. It is designed for First-In-First-Out (FIFO) data processing. When instantiating a Queue, you must provide a $queueType (a string representing the expected type or class name) to ensure type safety for all elements added to the queue.

    Key behaviors:

    • Type Safety: Adding an element of the wrong type via add() or array offset assignment will throw a Ramsey\Collection\Exception\InvalidArgumentException.
    • Non-throwing Offer: The offer() method attempts to add an element but returns false instead of throwing an exception if the type is incorrect.
    • Empty Queue Handling: Methods like element() and remove() throw a Ramsey\Collection\Exception\NoSuchElementException if called on an empty queue, whereas peek() and poll() return null.
    use Ramsey\Collection\Queue;
    
    // Create a queue for strings
    $queue = new Queue('string');
    
    // Add elements
    $queue->add('first');
    $queue->offer('second');
    
    // Peek at the first element without removing it
    echo $queue->peek(); // 'first'
    
    // Remove and return the first element
    echo $queue->poll(); // 'first'
    
    // Get the current head element (throws exception if empty)
    echo $queue->element();
  9. Queue API Reference

    main

    The Ramsey\Collection\Queue class provides the following public methods for managing queue elements:

    MethodReturn TypeDescription
    __construct(string $queueType, array $data = [])voidInitializes the queue with a specific type and optional initial data.
    add(mixed $element): boolboolAdds an element to the end of the queue. Throws InvalidArgumentException if type mismatch.
    element(): mixedTReturns the head element. Throws NoSuchElementException if the queue is empty.
    offer(mixed $element): boolboolAttempts to add an element. Returns true on success, false if the type is invalid.
    peek(): mixed|nullT|nullReturns the head element without removing it. Returns null if the queue is empty.
    poll(): mixed|nullT|nullRemoves and returns the head element. Returns null if the queue is empty.
    remove(): mixedTRemoves and returns the head element. Throws NoSuchElementException if the queue is empty.
    getType(): stringstringReturns the type or class name associated with this queue.
  10. Queue Exceptions

    main

    When working with Ramsey\Collection\Queue, you should handle the following exceptions:

    • Ramsey\Collection\Exception\InvalidArgumentException: Thrown by add() or offsetSet() when an element does not match the $queueType defined during construction.
    • Ramsey\Collection\Exception\NoSuchElementException: Thrown by element() or remove() when attempting to retrieve an item from an empty queue.