Библиотека для удобной работы с массивами данных различных структур с использованием функционального подхода. В основе лежат структуры данных, такие как: Список, Карта, Множество, Стек, Очередь.
Для обхода и преобразования коллекций используется stream api (Stream), который обеспечивает функциональный подход.
Читать на других языках: English
Установить и использовать библиотеку в собственном проекте можно использовав менеджер зависимостей Composer
composer require worksolutions/php-collections
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
// Отобрать элементы по фильтру
CollectionFactory::from([1, 2, 3])
->stream()
->filter(Predicates::greaterThan(1))
->getCollection(); // Collection [2, 3]
// Распечатать все файлы в директории
CollectionFactory::fromIterable(new DirectoryIterator(__DIR__))
->stream()
->each(static function (SplFileInfo $fileInfo) {
echo $fileInfo->getFilename() . "\n";
});
В основе использования библиотеки лежит последовательный подход обработки и преобразования данных. Создание некого конвейера преобразования, где можно последовательно выполнять некие шаги. Каждый шаг отвечает только за свой небольшой кусочек работы. В этом случае шаги можно переиспользовать так как они являются атомарными.
Фундаментально библиотека состоит из нескольких частей, это:
- Структуры данных. Каждая имеет свою особенность, выраженную при помощи интерфейса и описания к нему, и реализацию. При этом реализации поведения структур данных могут быть разные.
- Фабрика создания коллекции. Имеет множество статических методов для удобного создания коллекций.
- Потоки обхода коллекций. Предназначен для обхода и преобразования коллекций, при этом каждое преобразование создает новый экземпляр коллекции.
- Набор функций обхода и преобразования. Состоит из заранее подготовленных конструкторов функций для удобного использования в момент обхода. На их примере можно создать и использовать собственные функции более специфичные для вашей предметной области.
В основе библиотеки лежат самые популярные структуры данных которые являются самодостаточными для использования без каких-либо посторонних библиотек и классов. Все остальные части библиотеки основываются на эти структуры, в частности на интерфейс Collection
. Все структуры данных коллекций содержат множество элементов с которыми можно проводить основные процедуры, такие как: обход, преобразование, агрегирования и т.д.
- Коллекция (Collection)
- Список (ListSequence)
- Множество (Set)
- Очередь (Queue)
- Стек (Stack)
- Карта (Map)
Основной базовый интерфейс коллекций. Все структуры данных кроме карт (Map)
реализуют этот интерфейс, весь дополнительный функционал (Фабрики, Потоки обхода) используют данный интерфейс. Для поддержания универсальности в своих приложениях рекомендуется использовать именно интерфейс Collection
, но только в том случае если это не противоречит назначению использования структуры.
Коллекции доступны для обхода при помощи цикла foreach
.
- add – Добавление элемента в коллекцию
- addAll – Добавление множества элементов в коллекцию
- merge – Слияние коллекций
- clear – Удаление всех элементов коллекции
- remove – Удаление элемента коллекции
- contains – Проверка на существование элемента в коллекции
- equals – Сравнение двух коллекций на эквивалентность
- size – Получение количества элементов в коллекции
- isEmpty – Проверка коллекции на пустоту
- toArray – Получение элементов коллекции в виде массива
- copy – Получение копии коллекции
- stream – Получение потока обхода коллекции (Stream)
- Обход коллекции при помощи цикла foreach
add($element: mixed): bool;
Добавляет элемент в конец коллекции. Возвращает true
в случае успешного ответа или false
при неудаче.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2]); // [1, 2]
$collection->add(10); // [1, 2] -> [1, 2, 10];
addAll($elements: iterable): bool;
Добавляет множества элементов в конец коллекции. Возвращает true
в случае успешного ответа или false
при неудаче.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2]); // [1, 2]
$collection->add([10, 11, 12]); // true
$collection->toArray(); // [1, 2] -> [1, 2, 10, 11, 12];
merge($collection: Collection): bool;
Метод объединяет текущую коллекцию с переданной. Возвращает true
в случае успешного ответа или false
при неудаче.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2]); // [1, 2]
$mergingCollection = CollectionFactory::from([11, 12]); // [11, 12]
$collection->merge($mergingCollection); // true
$collection->toArray(); // [1, 2, 10, 11, 12];
clear(): void;
Метод удаляет все элементы коллекции.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2]); // [1, 2]
$collection->clear(); // null
$collection->toArray(); // [];
remove($element: mixed): bool;
Удаление конкретного элемента в коллекции. Метод возвращает признак удаления элемента. Если элемента не существовало, вернется false
.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection->remove(2); // true
$collection->remove(4); // false
$collection->toArray(); // [1, 3];
contains($element: mixed): bool;
Проверка наличия конкретного элемента в коллекции. Если элемента не существует, вернется false
.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection->contains(2); // true
$collection->contains(4); // false
equals($collection: Collection): bool;
Метод проверяет, что переданная коллекция эквивалентна текущей, это означает что все элементы одной коллекции содержатся в другой коллекции и количество элементов равно. В случае неравенства коллекций, вернется false
.
use WS\Utils\Collections\HashSet;
$set1 = new HashSet([1, 2, 3]);
$set2 = new HashSet([3, 2, 1]);
$set3 = new HashSet([3, 2]);
$set1->equals($set2); // true
$set2->equals($set1); // true
$set1->equals($set3); // false
size(): int;
Метод возвращает число элементов в коллекции. Если коллекция пустая - 0.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection->size(); // 3
$emptyCollection = CollectionFactory::from([]);
$emptyCollection->size(); // false
isEmpty(): bool;
Метод возвращает признак пустой коллекции. Если в коллекции существуют элементы, вернется false
.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection->isEmpty(); // false
$emptyCollection = CollectionFactory::from([]);
$emptyCollection->isEmpty(); // true
toArray(): array;
Метод индексированный массив состоящий из элементов коллекции, порядок следования элементов зависит от внутреннего представления.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection->toArray(); // [1, 2, 3]
$emptyCollection = CollectionFactory::from([]);
$emptyCollection->toArray(); // []
copy(): Collection;
Метод возвращает точную копию коллекции. Коллекции - мутабельны. Это означает, что применение методов модификации изменяет коллекцию, для гарантии неизменности коллекции рекомендуется применять метод копирования.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$copyOfCollection = $collection->copy(); // Collection
$copyOfCollection === $collection; // false
stream(): Stream;
Метод объект который реализует интерфейс обхода коллекции (Stream). Поток обхода коллекции является очень мощным инструментом и в большинстве случаев при разработке приходится иметь дело именно с ним. [Подробнее...](#Поток обхода коллекции)
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
$collection
->stream()
->each(static function (int $el) {var_export($el);}); // 1 2 3
Коллекции доступны для обхода при в цикле foreach. Порядок перебора коллекции зависит от внутренней реализации конкретного класса.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::from([1, 2, 3]); // [1, 2, 3]
foreach($collection as $item) {
var_export($item);
}
Списком является структура данных в которой строго определен порядок элементов. Списки с одинаковым набором элементов и разной их последовательностью не равны. Интерфейс ListSequence расширяет интерфейс Collection.
Интерфейс списка (ListSequence) расширяет интерфейсы: Collection
Интерфейс списка (ListSequence) реализуют классы: ArrayList, ImmutableList
- get – Получение элемента по порядковому индексу
- set – Замена элемента списка
- indexOf – Получение порядкового индекса элемента
- lastIndexOf – Получение порядкового индекса последнего подходящего элемента
- removeAt – Удаление элемента по индексу
get($index: int): mixed;
Метод возвращает элемент по индексу. Если по индексу элемента не существует, вернет null. Первый элемент списка имеет индекс 0.
use WS\Utils\Collections\ArrayList;
$list = ArrayList::of(1, 2);
$list->get(0); // 1
$list->get(1); // 2
$list->get(2); // null
set($element: mixed, $index: int): mixed;
Метод заменяет элемент по индексу. Возвращает значение элемента который был заменен текущим методом. Если происходит попытка заменить не существующий элемент, OutOfRangeException будет выброшен.
use WS\Utils\Collections\ArrayList;
$list = ArrayList::of(1, 2);
$list->set(3, 0); // 1
$list->set(4, 1); // 2
$list->set(4, 2); // OutOfRangeException
indexOf($element: mixed): ?int;
Метод возвращает первый индекс найденного элемента. В случае отсутствия значения в списке, вернется null
.
use WS\Utils\Collections\ArrayList;
$list = ArrayList::of(1, 2, 1, 3);
$list->indexOf(1); // 0
$list->indexOf(2); // 1
$list->indexOf(4); // null
lastIndexOf($element: mixed): ?int;
Метод возвращает последний индекс найденного элемента. В случае отсутствия значения в списке, вернется null
.
use WS\Utils\Collections\ArrayList;
$list = ArrayList::of(1, 2, 1, 3);
$list->indexOf(1); // 2
$list->indexOf(2); // 1
$list->indexOf(3); // null
removeAt(int $index): mixed;
Метод удаляет элемент по индексу, элементы находящиеся после удаленного индекса перемещаются ближе к началу на одну позицию. Возвращает значение удаленного элемента. В случае отсутствия элемента по индексу вернется null
.
use WS\Utils\Collections\ArrayList;
$list = ArrayList::of(1, 2, 1, 3);
$list->removeAt(1); // 2
$list->toArray(); // [1, 1, 3]
Множество содержит только уникальные элементы, порядок следования элементов может быть любым. То есть добавление элемента методом add
не гарантирует его последнее место среди остальных элементов при итерировании и в случае наличия элемента с таким же значением, последний не добавится в множество.
Уникальность определяется значением, а для объектов либо уникальностью конкретного объекта, либо в случае если объект реализует интерфейс HashCodeAware
уникальностью результата вызова метода getHashCode(): string;
.
Интерфейс множества (Set) расширяет интерфейсы: Collection
Интерфейс множества (Set) реализуют классы: HashSet
Такая структура данных как очередь удобна для последовательной обработки данных в порядке поступления. Она обладает удобными методами добавления и потребления элементов. Первый элемент, который попал в очередь - первым ее и покинет.
Интерфейс очереди (Queue) расширяет интерфейсы: Collection
Интерфейс очереди (Queue) реализуют классы: ArrayQueue
- offer – Вставка элемента в очередь
- poll – Получение элемента и удаление его из очереди
- peek – Получение элемента без удаления его из очереди
offer($element): bool;
Метод добавляет элемент в конец очереди. Возвращает false
если элемент не был добавлен, возможно в случае ограниченной очереди.
use WS\Utils\Collections\ArrayQueue;
$queue = ArrayQueue::of(1, 2);
$queue->offer(3); // [1, 2, 3]
$queue->peek(); // 3
poll(): mixed;
Метод возвращает элемент и удаляет его из начала очереди. В случае отсутствия элементов в очереди будет выброшено исключение RuntimeException
.
use WS\Utils\Collections\ArrayQueue;
$queue = ArrayQueue::of(1, 2);
$queue->peek(); // 2
$queue->poll(); // [1]
$queue->peek(); // 1
poll(): mixed;
Метод возвращает элемент. Очередь при этом не изменяется, элемент остается на своем месте. В случае отсутствия элементов в очереди будет выброшено исключение RuntimeException
.
use WS\Utils\Collections\ArrayQueue;
$queue = ArrayQueue::of(1, 2, 3);
$queue->peek(); // 2
$queue->size(); // 3
Стек является структурой данных логика работы которой противоположна логике работы очереди. Первый элемент попавшей в стек будет первым и извлечен из него.
Интерфейс стека (Stack) расширяет интерфейсы: Collection
Интерфейс стека (Stack) реализуют классы: ArrayStack
- push – Добавление элемента
- pop – Получение последнего добавленного элемента
- peek – Получение последнего добавленного элемента без модификации стека
push($element: mixed): bool;
Метод добавляет элемент на вершину стека. Возвращает false
если элемент не был добавлен, возможно в случае ограничений.
use WS\Utils\Collections\ArrayStack;
$queue = ArrayStack::of(1, 2);
$queue->push(3); // [1, 2, 3]
$queue->peek(); // 3
pop(): mixed;
Метод возвращает элемент с вершины стека. На вершину стека остается элемент добавленный перед полученным. В случае отсутствия элементов в стеке будет выброшено исключение RuntimeException
.
use WS\Utils\Collections\ArrayStack;
$queue = ArrayStack::of(1, 2, 3); // [1, 2, 3]
$queue->pop(); // 3
$queue->pop(); // 2
$queue->push(4); // [1, 4]
$queue->pop(); // 4
$queue->peek(); // 1
peek(): mixed;
Метод возвращает элемент который расположен на вершине стека. В случае отсутствия элементов в стеке будет выброшено исключение RuntimeException
.
use WS\Utils\Collections\ArrayStack;
$queue = ArrayStack::of(1, 2, 3); // [1, 2, 3]
$queue->pop(); // 3
$queue->peek(); // 3
$queue->peek(); // 3
$queue->pop(); // 2
$queue->pop(); // 1
$queue->peek(); // RuntimeException
Карта представляет отображение или иначе говоря словарь, где каждый элемент представляет пару "ключ-значение". Ключи карты уникальны по значению, если это объекты, то уникальность достигается либо уникальностью ссылки на объект, либо в случае если объект реализует интерфейс HashCodeAware
уникальностью результата вызова метода getHashCode(): string;
.
Интерфейс карты (Map) расширяет интерфейсы: IteratorAggregate
Интерфейс карты (Map) реализуют классы: HashMap
- put – Добавление пары ключ/значение
- get – Получение значения пары по ключу
- keys – Получение коллекции ключей карты
- values – Получение коллекции значений карты
- remove – Удаление пары по ключу
- containsKey – Признак наличия пары по ключу
- containsValue – Признак наличия пары по значению
- size – Количество пар в карте
- stream – Получение потока обхода коллекции пар ключ/значение (Stream)
- Обход объекта map при помощи цикла foreach
put($key: mixed, $value: mixed): bool;
Метод добавляет пару ключ/значение в объект структуры. Возвращает false
если элемент не был добавлен, возможно в случае ограничений. Как ключом так и значением могут быть данные скалярных типов, массивы и объекты.
use WS\Utils\Collections\HashMap;
$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);
foreach ($map as $k => $v) {
var_dump($k); // one | two
var_dump($v); // 1 | 2
}
get($key): mixed;
Метод возвращает значение пары по ключу key
. В случае, если значения нет вернется null
.
use WS\Utils\Collections\HashMap;
$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);
$map->get('one'); // 1
$map->get('three'); // null
keys(): Collection<mixed>;
Метод возвращает коллекцию состоящую из всех ключей карты.
use WS\Utils\Collections\HashMap;
$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);
foreach ($map->keys() as $k) {
var_dump($k); // one | two
}
values(): Collection<mixed>;
Метод возвращает коллекцию состоящую из всех значений пар карты.
use WS\Utils\Collections\HashMap;
$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);
foreach ($map->keys() as $v) {
var_dump($v); // 1 | 2
}
remove($key: mixed): bool;
Метод удаляет пару из карты по ключу key
.
use WS\Utils\Collections\HashMap;
$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);
$map->remove('one');
foreach ($map->keys() as $v) {
var_dump($v); // 2
}
containsKey($key: mixed): bool;
Метод возвращает признак наличия пары с ключом key
.
use WS\Utils\Collections\HashMap;
$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);
$map->containsKey('one'); // true
containsValue($value: mixed): bool;
Метод возвращает признак наличия пары со значением value
.
use WS\Utils\Collections\HashMap;
$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);
$map->containsValue(1); // true
$map->containsValue(3); // false
size(): int;
Метод возвращает количество пар.
use WS\Utils\Collections\HashMap;
$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);
$map->size(); // 2
$emptyMap = new HashMap();
$map->size(); // 0
stream(): Stream;
Метод возвращает объект, который реализует интерфейс обхода (Stream). Элементами коллекции потока являются объекты пар ключ/значение KeyPair
. [Подробнее...](#Поток обхода коллекции)
use \WS\Utils\Collections\HashMap;
use \WS\Utils\Collections\MapEntry;
$map = new HashMap();
$map->put('one', 1);
$map->put('two', 2);
$map->put('tree', 3);
$map->stream()->each(static function (MapEntry $mapEntry) {
var_export($mapEntry->getKey()); // 'one', 'two', 'three'
var_export($mapEntry->getKey()); // 1 , 2 , 3
});
Объект типа Map можно итерировать в цикле foreach. В этом случае ключи и значения будут оригинальные. Таким образом ключом может быть любой тип кроме массива.
use \WS\Utils\Collections\HashMap;
$map = new HashMap();
$map->put(new SplObjectStorage(), 1);
$map->put(null, 2);
$map->put(false, 3);
$map->put(true, 4);
$map->put(0, 5);
foreach($map as $key => $value) {
var_export($key); // object of SplObjectStorage class| null| false| true| 0
var_export($value); // 1 | 2 | 3 | 4 | 5
}
Фабрики CollectionFactory/MapFactory
позволяют создавать объекты коллекций без использования конструктора конкретной реализации, а так же обладает другими удобными методами создания объектов коллекций.
На данный момент основной структурой библиотеки являются ArrayList, HashMap, HashSet
, которые и порождается фабрикой в статических методах.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;
CollectionFactory::numbers(10)
->stream()
->each(Consumers::dump()); // dumps int(0), int(1), ...
- CollectionFactory::from – Генерирование коллекции из массива элементов
- CollectionFactory::fromIterable – Генерирование коллекции при помощи любой итерируемой величины
- CollectionFactory::numbers – Генерирование коллекции состоящей из элементов последовательности целых чисел
- CollectionFactory::generate – Генерирование коллекции при помощи генератора
- MapFactory::fromIterable – Генерирование карты при помощи любого итерируемого значения
- MapFactory::assoc – Генерирование карты из ассоциативного массива
[↑ Фабрика создания коллекции]
from($values: array): Collection
Метод создает коллекцию элементы которой состоят из элементов переданного массива.
На данный момент реализацией коллекции является ArrayList
, в будущем конкретная реализация может поменяться, при вызове данного метода стоит опираться только на интерфейс Collection
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;
CollectionFactory::from([1 ,2, 3])
->stream()
->each(Consumers::dump()); // dumps int(1), int(2), int(3)
[↑ Фабрика создания коллекции]
fromIterable($iterable: iterable): Collection
Метод создает коллекцию элементы которой состоят из элементов переданного итератора.
На данный момент реализацией коллекции является ArrayList
, в будущем конкретная реализация может поменяться, при вызове данного метода стоит опираться только на интерфейс Collection
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;
use WS\Utils\Collections\Functions\Converters;
CollectionFactory::fromIterable(new DirectoryIterator(__DIR__))
->stream()
->map(Converters::toPropertyValue('filename'))
->each(Consumers::dump()); // Dumps strings with filenames
CollectionFactory::numbers - Генерирование коллекции состоящей из элементов последовательности целых чисел
[↑ Фабрика создания коллекции]
numbers($from: int, $to: ?int): Collection
Метод создает коллекцию, элементы которой состоят из последовательности целых чисел [$from .. $to]
. Если параметр $to
не передан, вернется коллекция [0 .. $from]
.
На данный момент реализацией коллекции является ArrayList
, в будущем конкретная реализация может поменяться, при вызове данного метода стоит опираться только на интерфейс Collection
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;
CollectionFactory::numbers(10, 15)
->stream()
->each(Consumers::dump()); // Dumps [10, 11, 12, 13, 14, 15]
[↑ Фабрика создания коллекции]
generate($times: int, $generator: ?callable): Collection
Метод создает коллекцию размерности $times
, элементы которой состоят из значений результатов вызова генератора $generator
.
На данный момент реализацией коллекции является ArrayList
, в будущем конкретная реализация может поменяться, при вызове данного метода стоит опираться только на интерфейс Collection
. Если нужно конкретный тип экземпляра коллекций - нужно использовать конструкторы реализаций или их статические методы.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;
CollectionFactory::generate(3, static function () {
return random_int(0, 10);
})
->stream()
->each(Consumers::dump()); // Dumps for example [9, 7, 2]
[↑ Фабрика создания коллекции]
MapFactory::fromIterable($iterable: iterable): Map
Метод создает объект карты из любого итерируемого объекта.
use WS\Utils\Collections\MapFactory;
MapFactory::fromIterable(['a' => 1, 'b' => 2])
->keys() // ['a', 'b']
;
[↑ Фабрика создания коллекции]
MapFactory::assoc(array $assocArray): Map
Метод создает объект карты из ассоциативного массива.
use WS\Utils\Collections\MapFactory;
MapFactory::assoc(['a' => 1, 'b' => 2])
->keys() // ['a', 'b']
;
Для более удобного обхода и преобразования коллекций необходимо использовать потоки обхода коллекций (Stream). В основном все вычисления должны производится через stream. Для получения потока нужно вызвать метод коллекции Collection::stream()
.
Обработка коллекции при помощи stream происходит через выполнения функций, интерфейсы которых должны соответствовать назначению обхода/преобразования. Всего их шесть:
- Предикат (Predicate). Используется для фильтра элементов
filter
, элемент остается в коллекции потока (stream) в случае если предикат вызванный для данного элемента вернет булевое положительное значение. Библиотека уже содержит некоторые подготовленные предикаты. - Конвертер (Converter). Функции этого типа используются для преобразования коллекции потока
map
. Конвертер должен вернуть значение которое по некоторому признаку соответствует переданному элементу коллекции. Библиотека уже содержит некоторые подготовленные конвертеры. - Потребитель (Consumer). Функции потребителей не изменяют коллекцию потока, а используются для ее обхода
each
. Переданная функция будет вызвана для каждого элемента коллекции, результат выполнения функции не учитывается. Библиотека уже содержит некоторые подготовленные потребители. - Функции сравнения (Comparator). Компораторы участвуют в сортировке элементов для определения порядка сортировки двух значений. Должна возвращать целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй. php.net usort. Библиотека уже содержит некоторые подготовленные функции сравнения.
- Преобразователь (Reorganizer). Функции преобразователей преобразуют одну коллекцию в другую
reorganize
не изменяя при этом объекта потока. Преобразования необходимы когда нужно получить итоговую коллекцию не просто преобразовывая один элемент в другой, а сформировать новую коллекцию основываясь на всей информации исходной коллекции. Примером могут служить методы перемешиванияshuffle
элементов или формирования порцийchunk
. Библиотека уже содержит некоторые подготовленные преобразователи. - Функции сбора данных (Collector). Функции сбора данных применяются к потоку при помощи метода
collect
, по сути результат выполнения функций этой группы и будет являться результатом выполнения потока. Методcollect
является терминальным, то есть вызовом этого метода поток обрывается.
Все потоки принадлежат интерфейсу Stream
, это означает что описание интерфейса гарантирует его корректное исполнение вне зависимости от конкретной реализации, исключения лишь составляют частные случаи поведения потоков (when
).
Stream`s гарантируют, что после каждого метода модификации метод getCollection
будет возвращать разные экземпляры объектов, что является надежным способом с точки зрения безопасности для поддержания иммутабельности при преобразовании.
- each – Обход элементов коллекции
- walk – Ограниченный обход элементов коллекции
- filter – Фильтрация элементов коллекции
- map – Отражение элементов коллекции потока
- reorganize – Преобразование коллекции потока
- collect – Сбор данных коллекции
- sort – Сортировка элементов коллекции
- sortBy – Сортировка элементов коллекции по значению
- sortDesc – Сортировка элементов коллекции в обратном порядке
- sortByDesc – Сортировка элементов коллекции по значению в обратном порядке
- reduce – Сокращение коллекции в единое значение
- when – Ограничение модификации потока по условию
- always – Отмена ограничений модификации потока
- getCollection – Получение коллекции потока
- allMatch – Полное совпадение всех элементов по предикату
- anyMatch – Частичное совпадение всех элементов по предикату
- findAny – Получение произвольного элемента коллекции
- findFirst – Получение первого элемента коллекции
- findLast – Получение последнего элемента коллекции
- min – Получение минимального элемента коллекции
- max – Получение максимального элемента коллекции
- reverse – Расположить элементы коллекции в обратном порядке
- limit – Сократить коллекцию до указанного размера
each($consumer: <fn($element: mixed, $index: int): void>): Stream;
Метод применяет к каждому элементу коллекции потока, функцию $consumer. Результат выполнения функции не учитывается. Вызов метода each
не изменяет коллекцию потока, но в то же время получает доступ к каждому элементу в коллекции.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;
CollectionFactory::numbers(10)
->stream()
->each(Consumers::dump()) // dumps each element
->each(static function ($el) { // prints strings 0, 1, 2, 3
echo $el."\n";
})
;
walk($consumer: <fn($element: mixed, $index: int): false|void>, $limit: ?int): Stream;
Метод применяет к каждому элементу коллекции потока, функцию $consumer
, так же как и в методе each
. Результат выполнения функции не учитывается. Вызов метода each
не изменяет коллекцию потока, но в то же время получает доступ к каждому элементу в коллекции.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;
CollectionFactory::numbers(10)
->stream()
->walk(Consumers::dump(), 5) // dumps only first 5 elements: 0, 1, 2, 3, 4
->walk(static function ($el) { // prints strings 0, 1, 2, 3. Method will be called only 5 times
if ($el === 4) {
return false;
}
echo $el."\n";
})
;
filter($predicate: <fn($element: mixed): bool>): Stream;
Метод применяет к каждому элементу коллекции потока, функцию $predicate
. В случае если вызов предиката с элементов вернет отрицательный результат - false, 0, '', []
, элемент исключается из коллекции.
use WS\Utils\Collections\CollectionFactory;
CollectionFactory::numbers(10)
->stream()
->filter(static function (int $el): bool {
return $el % 2 === 0;
})
->getCollection() // returns only first 5 elements: 0, 2, 4, 6, 8
;
map($converter: <fn($element: mixed): mixed>): Stream;
Метод применяет к каждому элементу коллекции потока, подменяет переданные элементы коллекции на результаты выполнения функции.
use WS\Utils\Collections\CollectionFactory;
CollectionFactory::numbers(10)
->stream()
->map(static function (int $el): int {
return $el * 10;
})
->getCollection() // returns 0, 10, 20, 30, 40, 50, 60, 70, 80, 90
;
reorganize($reorganizer: <fn($collection: Collection): Collection>): Stream;
Метод применяет $reorganizer
к внутренней коллекции, затем заменяет внутреннюю коллекцию на результат вызова метода. Необходим когда следует выполнить преобразования основываясь на данных полной коллекции.
use WS\Utils\Collections\ArrayStack;
use WS\Utils\Collections\Collection;
use WS\Utils\Collections\CollectionFactory;
CollectionFactory::numbers(10)
->stream()
// reverse collection
->reorganize(static function (Collection $collection): Collection {
$stack = new ArrayStack();
foreach ($collection as $item) {
$stack->push($item);
}
$reversed = CollectionFactory::empty();
while (!$stack->isEmpty()) {
$reversed->add($stack->pop());
}
return $reversed;
})
->getCollection()
;
collect($collector: <fn ($collection: Collection): mixed>): mixed;
Метод применяет $collector
к внутренней коллекции и возвращает результат. Необходим, когда необходимо выполнить финальное действие над коллекцией с использованием потока. Терминальный метод.
use WS\Utils\Collections\Collection;
use WS\Utils\Collections\CollectionFactory;
$sumOfElements = CollectionFactory::numbers(10)
->stream()
// get sum of collection elements
->collect(static function (Collection $collection): int {
$res = 0;
foreach ($collection as $item) {
$res += $item;
}
return $res;
})
;
sort($comparator: <fn($a: mixed, $b: mixed): int>): Stream;
Метод сортирует элементы согласно работе $comparator
(компаратора). Компоратор определяет порядок сортировки двух значений. Должен возвращать целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй. php.net usort
use WS\Utils\Collections\CollectionFactory;
$sortedCollection = CollectionFactory::generate(10, static function (): int {
return random_int(0, 100);
})
->stream()
// get sorted collection
->sort(static function (int $a, int $b): int {
return $a <=> $b;
})
->getCollection()
;
sort($comparator: <fn($a: mixed, $b: mixed): int>): Stream;
Метод сортирует элементы согласно работе $comparator
(компаратора), но в отличии от обычной функции сортировки элемнты будут выстроены по убыванию. Компоратор определяет порядок сортировки двух значений. Должен возвращать целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй. php.net usort
use WS\Utils\Collections\CollectionFactory;
$sortedDescendentCollection = CollectionFactory::generate(10, static function (): int {
return random_int(0, 100);
})
->stream()
// get sorted collection in the reverse order
->sortDesc(static function (int $a, int $b): int {
return $a <=> $b;
})
->getCollection()
;
sortBy($extractor: <fn($el: mixed): scalar>): Stream;
Метод сортирует элементы согласно полученному значению функции $extractor
для каждого элемента. Функция должна вернуть скалярное значение для возможности независимой оптимизированной сортировки. Аналогично работает метод сортировки по значению в обратном порядке sortByDesc
.
use WS\Utils\Collections\CollectionFactory;
class Container {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
$sortedCollection = CollectionFactory::generate(10, static function (): Container {
return new Container(random_int(0, 100));
})
->stream()
// get sorted collection
->sortBy(static function (Container $container): int {
return $container->getValue();
})
->getCollection()
;
reduce($accumulator: <fn($el: mixed, $carry: mixed): mixed>): mixed;
Метод приводит коллекцию к единому значению. Функции передаются значения $el
итерируемого элемента и результат вызова этой же функции на предыдущем элементе $carry
. В первой итерации $carry === null
. Терминальный метод.
use WS\Utils\Collections\CollectionFactory;
$sumOfCollection = CollectionFactory::numbers(10)
->stream()
// get sum of collection elements
->reduce(static function (int $el, ?int $carry = null): int {
return $carry + $el;
})
;
when($condition: bool): Stream;
Метод ограничивает модификацию при невыполнении условия $condition
и все методы модификации и обхода не будут вызываться. Обратный метод - always
.
Блокируемые методы:
- each
- walk
- filter
- reorganize
- map
- sort
- sortBy
- sortDesc
- sortDescBy
- reverse
- limit
use WS\Utils\Collections\Collection;
use WS\Utils\Collections\CollectionFactory;
$randomElementSizeCollection = CollectionFactory::numbers(random_int(0, 20));
$onlyTenElements = $randomElementSizeCollection
->stream()
// get collection elements only 10 items
->when($randomElementSizeCollection->size() > 10)
->limit(10)
->when($randomElementSizeCollection->size() < 10)
->reorganize(static function (Collection $collection) {
for ($i = $collection->size(); $i < 10; $i++ ) {
$collection->add($i);
}
return $collection;
})
;
always(): Stream;
В случае если поток был заблокирован ранее для модификаций через условие when
, метод always
отменяет ограничения на дальнейший вызов модифицирующих методов.
use WS\Utils\Collections\CollectionFactory;
$collection = CollectionFactory::numbers(20);
$onlyTenElements = $collection
->stream()
// get collection elements only 10 items
->when($collection->size() > 5)
->limit(5)
->always()
->map(static function (int $el): int {
return $el * 10;
})
->getCollection() // [0, 10, 20, 30, 40]
;
getCollection(): Collection;
Метод возвращает коллекцию с учетом ранее выполненных преобразований. Даже если в потоке будут еще вызваны методы преобразования, полученная коллекция останется не измененной. Терминальный метод.
use WS\Utils\Collections\CollectionFactory;
$stream = CollectionFactory::numbers(10)
->stream();
$collection1 = $stream
->map(static function (int $el): int{
return $el * 10;
})
->getCollection()
;
$collection2 = $stream
->filter(static function (int $el): bool {
return $el > 50;
})
->getCollection()
;
$collection1->size() === $collection2->size(); // false
$collection2->toArray(); // [60, 70, 80, 90]
allMatch($predicate: <fn($el: mixed): bool>): bool;
Метод вернет true
, если все вызовы $predicate
над элементами коллекции будут истинными (true
). Терминальный метод.
use WS\Utils\Collections\CollectionFactory;
CollectionFactory::numbers(10)
->stream()
->allMatch(static function (int $el): bool {
return $el >= 1;
}) // false, 0 is less than 1
;
anyMatch(callable $predicate): bool;
Метод вернет true
, если хотя бы один вызов $predicate
над элементами коллекции будет истинным (true
). Терминальный метод.
use WS\Utils\Collections\CollectionFactory;
CollectionFactory::numbers(10)
->stream()
->anyMatch(static function (int $el): bool {
return $el > 0;
}) // true, [1, 2, 3, 4, 5, 6, 7, 8, 9] are grate than 0
;
findAny(): mixed;
Метод вернет произвольный элемент коллекции, либо null
, если коллекция пустая. Не гарантирует того что элемент выбирается в случайном порядке. Терминальный метод.
use WS\Utils\Collections\CollectionFactory;
CollectionFactory::numbers(10)
->stream()
->findAny() // for example - 5
;
findFirst(): mixed;
Метод вернет первый элемент коллекции , либо null
, если коллекция пустая. Терминальный метод.
use WS\Utils\Collections\CollectionFactory;
CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
->stream()
->findFirst() // 0
;
findLast(): mixed;
Метод вернет последний элемент коллекции , либо null
, если коллекция пустая. Терминальный метод.
use WS\Utils\Collections\CollectionFactory;
CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
->stream()
->findLast() // 9
;
min($comparator: <fn($a: mixed, $b: mixed): int>): mixed;
Метод вернет наименьший элемент коллекции согласно сравнению функции компоратора, либо null
, если коллекция пустая. Терминальный метод.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;
CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
->stream()
->reorganize(Reorganizers::shuffle())
->min(static function (int $a, int $b): int {
return $a <=> $b;
}) // 0
;
max($comparator: <fn($a: mixed, $b: mixed): int>): mixed;
Метод вернет наибольший элемент коллекции согласно сравнению функции компоратора, либо null
, если коллекция пустая. Терминальный метод.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;
CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
->stream()
->reorganize(Reorganizers::shuffle())
->max(static function (int $a, int $b): int {
return $a <=> $b;
}) // 9
;
reverse(): Stream;
Метод преобразует порядок элементов в обратную последовательность.
use WS\Utils\Collections\CollectionFactory;
CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
->stream()
->reverse()
->getCollection() // [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
;
limit(int $size): Stream;
Метод сокращает количество элементов до указанного размера. В случае, если количество элементов уже меньше чем указано в ограничении $size
, количество элементов останется прежним.
use WS\Utils\Collections\CollectionFactory;
CollectionFactory::numbers(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
->stream()
->reverse()
->getCollection() // [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
;
Библиотека содержит конструкторы наиболее популярных функций, которые инициируют функции для из работы через потоки обхода и преобразования с заранее подготовленными параметрами. Например:
use \WS\Utils\Collections\Functions\Predicates;
$equal10Predicate = Predicates::equal(10);
$equal10Predicate(11); // false
$equal10Predicate(10); // true
Вызов конструктор функции Predicates::equal(10)
вернет функцию сравнения входного параметра со значением 10.
Функции применяемые в библиотеке разделены на следующие типы:
- Predicates – Предикаты
- Comparators - Функции сравнения
- Converters - Преобразователи элементов
- Reorganizers - Преобразователи потоков
- Consumers - Потребители
- Группировка и агрегация
Каждый тип функции должен иметь соответствующий интерфейс для использования в определенных методах потоков.
[↑ Набор функций обхода и преобразования]
Группа конструкторов функций которые используются для фильтрации коллекции потока. Все методы возвращают проинициализированные функции с интерфейсом: <Fn($el: mixed): bool>
. Предикаты также позволяют работать со свойствами объектов. К примеру под свойством объекта myPropety
подразумевается наличие публичного свойства в объекте с названием myProperty
либо наличие методе геттера
- getMyProperty
.
- lock – Блокировка
- notResistance – Пропуск всех значений
- notNull – Проверка значений на пустоту
- eachEven – Пропуск элементов чётных вызовов
- nth – Пропуск элементов кратных вызовов
- equal – Проверка на эквивалентность
- lockDuplicated – Блокировка значений дубликатов
- lessThan – Проверка значения на условие "меньше"
- lessOrEqual – Проверка значения на условие "меньше либо равно"
- greaterThan – Проверка значения на условие "больше"
- greaterOrEqual – Проверка значения на условие "больше либо равно"
- not – Проверка значения на неравенство
- in – Проверка значения на нахождение во множестве
- notIn – Проверка значения на отсутствие во множестве
- where – Проверка свойства объекта на эквивалентность
- whereNot – Проверка свойства объекта на неравенство
- whereIn – Проверка свойства объекта на нахождение во множестве
- whereNotIn – Проверка свойства объекта на отсутствие во множестве
- whereGreaterThan – Проверка свойства объекта на условие "больше"
- whereLessThan – Проверка свойства объекта на условие "меньше"
- whereGreaterOrEqual – Проверка свойства объекта на условие "больше либо равно"
- whereLessOrEqual – Проверка свойства объекта на условие "меньше либо равно"
lock(): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию, которая на любой набор входных данных - будет возвращать false. По сути метод порождает функцию блокирования потока.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
$lockFunction = Predicates::lock();
CollectionFactory::numbers(1, 10)
->stream()
->filter($lockFunction)
->getCollection()
->isEmpty() // true
;
notResistance(): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию, которая на любой набор входных данных - будет возвращать true
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
$passFunction = Predicates::notResistance();
CollectionFactory::numbers(1, 10)
->stream()
->filter($passFunction)
->getCollection()
->size() // 10
;
notNull(): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию, которая на любой набор входных данных - будет возвращать true
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
$notNullPassFunction = Predicates::notNull();
CollectionFactory::from([1, 10, null])
->stream()
->filter($notNullPassFunction)
->getCollection()
->size() // 2
;
eachEven(): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию, которая каждый четный вызов - будет возвращать true
и, соответственно, в остальных случаях - false
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
$evenPassFunction = Predicates::eachEven();
CollectionFactory::from([1, 2, 3, 4, null, false])
->stream()
->filter($evenPassFunction)
->getCollection()
->toArray() // 2, 4, false
;
nth($number: int): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию, которая каждый $number
вызов - будет возвращать true
и, соответственно, в остальных случаях - false
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
$thirdPassFunction = Predicates::nth(3);
CollectionFactory::from([1, 2, 3, 4, null, false])
->stream()
->filter($thirdPassFunction)
->getCollection()
->toArray() // 3, false
;
equal($value: mixed): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию, которая возвращает истинное значение при совпадении элемента коллекции со значением $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
CollectionFactory::from([1, 2, 3, 4, null, false])
->stream()
->filter(Predicates::equal(3))
->findFirst() // 3
;
lockDuplicated(): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию, которая возвращает истинное значение только для вызовов с уникальными элементами.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
CollectionFactory::from([3, 2, 3, 4, null, 3])
->stream()
->filter(Predicates::lockDuplicated())
->getCollection()
->toArray() // [3, 2, 4, null]
;
lessThan($value: scalar): Closure; \\ <Fn($el: scalar): bool>
Метод инициирует функцию сравнения элементов со значением $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
CollectionFactory::from([1, 2, 3, 4, null, 3])
->stream()
->filter(Predicates::lessThan(4))
->getCollection()
->toArray() // [1, 2, 3, null, 3]
;
lessOrEqual($value: scalar): Closure; \\ <Fn($el: scalar): bool>
Метод инициирует функцию сравнения элементов со значением $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
CollectionFactory::from([1, 2, 3, 4, null, 3])
->stream()
->filter(Predicates::lessOrEqual(2))
->getCollection()
->toArray() // [1, 2, null]
;
greaterThan($value: scalar): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию сравнения элементов со значением $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
CollectionFactory::from([1, 2, 3, 4, null, 3])
->stream()
->filter(Predicates::greaterThan(2))
->getCollection()
->toArray() // [3, 4, 3]
;
greaterOrEqual($value: scalar): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию сравнения элементов со значением $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
CollectionFactory::from([1, 2, 3, 4, null, 3])
->stream()
->filter(Predicates::greaterOrEqual(2))
->getCollection()
->toArray() // [2, 3, 4, 3]
;
not($value: mixed): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию проверки неравенства элементов коллекции со значением $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
CollectionFactory::from([1, 2, 3, 4, null, 3])
->stream()
->filter(Predicates::not(3))
->getCollection()
->toArray() // [1, 2, 4, null]
;
in($values: array): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию проверки нахождения элементов во множестве $values
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
CollectionFactory::from([1, 2, 3, 4, null, 3])
->stream()
->filter(Predicates::in([null, 3]))
->getCollection()
->toArray() // [3, null, 3]
;
notIn($values: array): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию проверки отсутствия элементов во множестве $values
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
CollectionFactory::from([1, 2, 3, 4, null, 3])
->stream()
->filter(Predicates::notIn([null, 3]))
->getCollection()
->toArray() // [1, 2, 4]
;
where($property: string, $value: mixed): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию проверки свойства объекта элемента на равенство значению $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
return new ValueObject($c++);
})
->stream()
->filter(Predicates::where('value', 0))
->getCollection()
->isEmpty() // false
;
whereNot($property: string, $value: mixed): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию проверки свойства объекта элемента на неравенство значению $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
return new ValueObject($c++);
})
->stream()
->filter(Predicates::whereNot('value', 0))
->getCollection()
->toArray() // [#1, #2, #3, #4]
;
whereIn($property: string, $values: array): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию проверки нахождения значения свойства объекта во множестве $values
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
return new ValueObject($c++);
})
->stream()
->filter(Predicates::whereIn('value', [0, 4, 9]))
->getCollection()
->toArray() // [#0, #4]
;
whereNotIn($property: string, $values: array): Closure; \\ <Fn($el: mixed): bool>
Метод инициирует функцию проверки отсутствия значения свойства объекта во множестве $values
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
return new ValueObject($c++);
})
->stream()
->filter(Predicates::whereIn('value', [0, 4, 9]))
->getCollection()
->toArray() // [#0, #4]
;
whereGreaterThan($property: string, $value: scalar): Closure; \\ <Fn($el: scalar): bool>
Метод инициирует функцию сравнения значения свойства объекта с $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
return new ValueObject($c++);
})
->stream()
->filter(Predicates::whereGreaterThan('value', 3))
->getCollection()
->toArray() // [#4]
;
whereLessThan($property: string, $value: scalar): Closure; \\ <Fn($el: scalar): bool>
Метод инициирует функцию сравнения значения свойства объекта с $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
return new ValueObject($c++);
})
->stream()
->filter(Predicates::whereLessThan('value', 3))
->getCollection()
->toArray() // [#0, #1, #2]
;
whereGreaterOrEqual($property: string, $value: scalar): Closure; \\ <Fn($el: scalar): bool>
Метод инициирует функцию сравнения значения свойства объекта с $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
return new ValueObject($c++);
})
->stream()
->filter(Predicates::whereGreaterOrEqual('value', 3))
->getCollection()
->toArray() // [#3, #4]
;
whereLessOrEqual($property: string, $value: scalar): Closure; \\ <Fn($el: scalar): bool>
Метод инициирует функцию сравнения значения свойства объекта с $value
.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Predicates;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
$c = 0;
CollectionFactory::generate(5, static function () use (& $c) {
return new ValueObject($c++);
})
->stream()
->filter(Predicates::whereLessOrEqual('value', 3))
->getCollection()
->toArray() // [#1, #2, #3]
;
[↑ Набор функций обхода и преобразования]
Группа конструкторов функций сравнения. Функции сравнения элементов необходимы при использовании методов сортировки, для того чтобы в правильном порядке расположить элементы. Итоговые функции сортировки имеют интерфейс <Fn($a: mixed, $b: mixed): int>
, с логикой работы идентичной [https://www.php.net/manual/ru/function.usort].
- scalarComparator – Сравнение скалярных значений
- objectPropertyComparator – Сравнение свойств объектов
- callbackComparator – Определение функции для сравнения значений
[↑ Comparators функции сравнения]
scalarComparator(): Closure; \\ <Fn($a: scalar, $b: scalar): int>
Метод инициирует функцию, которая сравнивает два значения. Функция сравнения возвращает целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Comparators;
CollectionFactory::generate(5, static function (): int {
return random_int(0, 10);
})
->stream()
->sort(Comparators::scalarComparator())
->getCollection()
->toArray() // sorted value, for example [2, 3, 6, 7, 8]
;
[↑ Comparators функции сравнения]
objectPropertyComparator($property: string): Closure; \\ <Fn($a: object, $b: object): int>
Метод инициирует функцию, которая сравнивает два значения свойства объектов. Функция сравнения возвращает целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Comparators;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
CollectionFactory::generate(5, static function () {
return new ValueObject(random_int(0, 10));
})
->stream()
->sort(Comparators::objectPropertyComparator('value'))
->getCollection()
->toArray() // sorted ValueObject objects, for example [#2, #3, #6, #7, #8]
;
[↑ Comparators функции сравнения]
callbackComparator($fun: <Fn($value: mixed): scalar>): Closure; \\ <Fn($a: mixed, $b: mixed): int>
Метод инициирует функцию, которая сравнивает два значения на основе их обработки функцией $fun
. Функция сравнения возвращает целое, которое меньше, равно или больше нуля, если первый аргумент является соответственно меньшим, равным или большим, чем второй.
use WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Comparators;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
CollectionFactory::generate(5, static function () {
return new ValueObject(random_int(0, 10));
})
->stream()
->sort(Comparators::callbackComparator(static function (ValueObject $valueObject) {
return $valueObject->getValue();
}))
->getCollection()
->toArray() // sorted ValueObject objects, for example [#2, #3, #6, #7, #8]
;
[↑ Набор функций обхода и преобразования]
Группа конструктор функций для преобразования элементов. Результатом функции конвертера является <Fn($obj: mixed): mixed>
.
- toPropertyValue – Преобразование каждого элемента коллекции в значение свойства
- toProperties – Преобразование каждого элемента коллекции в ассоциативный массив
[↑ Converters Преобразователи элементов]
toPropertyValue($property: string): Closure; \\ <Fn($obj: object): mixed>
Метод инициирует функцию, которая возвращает значение свойства объекта.
use WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Converters;
class ValueObject {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
CollectionFactory::generate(5, static function (int $index): ValueObject {
return new ValueObject($index);
})
->stream()
->map(Converters::toPropertyValue('value'))
->getCollection()
->toArray() // [0, 1, 2, 3, 4 ]
;
[↑ Converters Преобразователи элементов]
toProperties($names: array<string>): Closure; \\ <Fn($obj: object): array>
Метод инициирует функцию, которая возвращает ассоциативный массив свойств объекта, ключи которого являются именами свойств.
use WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Converters;
class Person {
private $name;
private $surname;
public function __construct(string $name, string $surname)
{
$this->name = $name;
$this->surname = $surname;
}
public function getName(): string
{
return $this->name;
}
public function getSurname(): string
{
return $this->surname;
}
}
CollectionFactory::generate(1, static function (int $index): Person {
return new Person('Ivan', 'Ivanov');
})
->stream()
->map(Converters::toProperties(['name', 'surname']))
->getCollection()
->toArray() // [['name' => 'Ivan', 'surname' => 'Ivanov']]
;
[↑ Набор функций обхода и преобразования]
Конструкторы методов преобразования потоков. В отличие от функций преобразования элементов, где каждому элементу исходной коллекции соответствует элемент новой коллекции с учетом позиции первого, методы преобразования потоков создают производную новую коллекцию с произвольным количеством элементов.
- shuffle – Смена порядка следования элементов коллекции
- random – Получение случайных элементов коллекции
- chunk – Разбиение на множество коллекций указанного размера
- collapse – Получение коллекции без дополнительных уровней вложенности
[↑ Reorganizers Преобразователи потоков]
shuffle(): Closure; \\ <Fn(): Collection>
Метод инициирует функцию, которая возвращает новую коллекцию с измененным порядком следования элементов. Элементы будут следовать в случайном порядке.
use \WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;
CollectionFactory::numbers(5)
->stream()
->reorganize(Reorganizers::shuffle())
->getCollection()
->toArray() // for example [0, 3, 1, 2, 4]
;
[↑ Reorganizers Преобразователи потоков]
random($count = 1: int): Closure; \\ <Fn(): Collection>
Метод инициирует функцию, функция возвращает новую коллекцию которая содержит случайное ограниченное множество элементов исходной коллекции.
use \WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;
CollectionFactory::numbers(5)
->stream()
->reorganize(Reorganizers::random(2))
->getCollection()
->toArray() // for example [0, 3]
;
[↑ Reorganizers Преобразователи потоков]
chunk($size: int): Closure; \\ <Fn(): Collection>
Метод инициирует функцию, функция возвращает коллекцию коллекций количество элементов которых меньше либо равно $size
.
use \WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;
CollectionFactory::numbers(10)
->stream()
->reorganize(Reorganizers::chunk(2))
->getCollection()
->toArray() // for example [[0, 1], [2, 3], ...]
;
[↑ Reorganizers Преобразователи потоков]
collapse(): Closure; \\ <Fn(): Collection>
Метод инициирует функцию, функция возвращает коллекцию без вложенных контейнеров. Под контейнерами в данном контексте понимаются итерируемые структуры данных.
use \WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Reorganizers;
CollectionFactory::generate(3, static function (int $i): array {
return [$i*2, $i*2 + 1];
}) // [[0, 1], [2, 3], [4, 5]]
->stream()
->reorganize(Reorganizers::collapse())
->getCollection()
->toArray() // for example [0, 1, 2, 3, 4, 5]
;
[↑ Набор функций обхода и преобразования]
Конструкторы функций потребителей. Содержит одну функцию распечатки значений элементов. В основном каждая функция потребитель разрабатывается индивидуально в исходном коде проекта.
dump(): Closure; \\ <Fn(): Collection>
Метод инициирует функцию, которая распечатывает в поток вывода переданное значение.
use \WS\Utils\Collections\CollectionFactory;
use WS\Utils\Collections\Functions\Consumers;
CollectionFactory::numbers(5)
->stream()
->each(Consumers::dump()) // dumps each element of collection
;
[↑ Набор функций обхода и преобразования]
$group = Group::by($fieldName): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 25],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'taxi', 'type' => 'transport', 'price' => 70],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 20],
];
$result = CollectionFactory::from($items)
->stream()
->collect(Group::by('type'))
;
/* Result ->
[
'groceries' => new \WS\Utils\Collections\ArrayList([
['name' => 'potato', 'type' => 'groceries', 'price' => 25],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
]),
'transport' => new \WS\Utils\Collections\ArrayList([
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'taxi', 'type' => 'transport', 'price' => 70],
]),
'entertainment' => new \WS\Utils\Collections\ArrayList([
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 20],
]),
];
*/
Group::addToSet($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 25],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'taxi', 'type' => 'transport', 'price' => 70],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 20],
];
$aggregation = Group::by('type')->addToSet('name', 'list');
$result = CollectionFactory::from($items)
->stream()
->collect($aggregation)
;
/* Result ->
[
'groceries' => ['list' => ['potato', 'milk']],
'transport' => ['list' => ['taxi']],
'entertainment' => ['list' => ['cinema']],
];
*/
Group::avg($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 30],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'taxi', 'type' => 'transport', 'price' => 50],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];
$aggregation = Group::by('type')->avg('price', 'avg');
$result = CollectionFactory::from($items)
->stream()
->collect($aggregation)
;
/* Result ->
[
'groceries' => ['avg' => 40],
'transport' => ['avg' => 75],
'entertainment' => ['avg' => 30],
];
*/
Group::count($destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 30],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'tea', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];
$aggregation = Group::by('type')->count('total');
$result = CollectionFactory::from($items)
->stream()
->collect($aggregation)
;
/* Result ->
[
'groceries' => ['total' => 3],
'transport' => ['total' => 1],
'entertainment' => ['total' => 2],
];
*/
Group::first($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 30],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'airplane', 'type' => 'transport', 'price' => 50],
['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];
$aggregation = Group::by('type')->first('name', 'item');
$result = CollectionFactory::from($items)
->stream()
->collect($aggregation)
;
/* Result ->
[
'groceries' => ['item' => 'potato'],
'transport' => ['item' => 'taxi'],
'entertainment' => ['item' => 'Knicks game'],
];
*/
Group::last($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 30],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'airplane', 'type' => 'transport', 'price' => 50],
['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];
$aggregation = Group::by('type')->last('name', 'item');
$result = CollectionFactory::from($items)
->stream()
->collect($aggregation)
;
/* Result ->
[
'groceries' => ['item' => 'milk'],
'transport' => ['item' => 'airplane'],
'entertainment' => ['item' => 'cinema'],
];
*/
Group::max($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 30],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'airplane', 'type' => 'transport', 'price' => 50],
['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];
$aggregation = Group::by('type')->max('price', 'max');
$result = CollectionFactory::from($items)
->stream()
->collect($aggregation)
;
/* Result ->
[
'groceries' => ['max' => 50],
'transport' => ['max' => 100],
'entertainment' => ['max' => 300],
];
*/
Group::min($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 30],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'airplane', 'type' => 'transport', 'price' => 50],
['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];
$aggregation = Group::by('type')->min('price', 'min');
$result = CollectionFactory::from($items)
->stream()
->collect($aggregation)
;
/* Result ->
[
'groceries' => ['min' => 30],
'transport' => ['min' => 50],
'entertainment' => ['min' => 30],
];
*/
Group::sum($sourceKey, $destKey): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 30],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'airplane', 'type' => 'transport', 'price' => 50],
['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];
$aggregation = Group::by('type')->sum('price', 'spent');
$result = CollectionFactory::from($items)
->stream()
->collect($aggregation)
;
/* Result ->
[
'groceries' => ['spent' => 80],
'transport' => ['spent' => 150],
'entertainment' => ['spent' => 330],
];
*/
Group::addAggregator($destKey, $callbackFn): Group;
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
use \WS\Utils\Collections\Collection;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 30],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'airplane', 'type' => 'transport', 'price' => 50],
['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];
$aggregation = Group::by('type')->addAggregator('names', function (Collection $collection) {
$result = [];
foreach ($collection as $item) {
$result[] = $item['name'];
}
return implode(', ', $result);
});
$result = CollectionFactory::from($items)
->stream()
->collect($aggregation)
;
/* Result ->
[
'groceries' => ['names' => 'potato, milk'],
'transport' => ['names' => 'taxi, airplane'],
'entertainment' => ['names' => 'Knicks game, cinema'],
];
*/
Все агрегаторы можно комбинировать между собой для получения желаемого результата.
use \WS\Utils\Collections\CollectionFactory;
use \WS\Utils\Collections\Functions\Group\Group;
$items = [
['name' => 'potato', 'type' => 'groceries', 'price' => 30],
['name' => 'milk', 'type' => 'groceries', 'price' => 50],
['name' => 'taxi', 'type' => 'transport', 'price' => 100],
['name' => 'airplane', 'type' => 'transport', 'price' => 50],
['name' => 'Knicks game', 'type' => 'entertainment', 'price' => 300],
['name' => 'cinema', 'type' => 'entertainment', 'price' => 30],
];
$aggregation = Group::by('type')->avg('price', 'avg')->min('price', 'min')->max('price', 'max');
$result = CollectionFactory::from($items)
->stream()
->collect($aggregation)
;
/* Result ->
[
'groceries' => ['avg' => 40, 'min' => 30, 'max' => 50],
'transport' => ['avg' => 75, 'min' => 50, 'max' => 100],
'entertainment' => ['avg' => 165, 'min' => 30, 'max' => 300],
];
*/