judahnator / iterable-collection
A fluent interface for working with iterables and generators.
Requires
- php: >=7.4
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.16.2
- phpstan/phpstan: ^0.12.54
- phpunit/phpunit: ^9.4
This package is auto-updated.
Last update: 2024-12-11 07:47:14 UTC
README
The Gist
This library allows you to use a fluent interface to manipulate iterable items.
The goal was to have at minimum feature parity with all the array_* functions, but the library falls a bit short of that goal due to a limitation of being unable to rewind generators. For that reason, some functions have been deliberately excluded.
Of course, if you can think of a good way to implement said functions feel free to submit a pull request.
A few additional functions were added as well that do not exist as native array_*
methods.
Usage
Object Creation:
$o = new IterableCollection(['foo' => 'bar']);
// or
$o = IterableCollection::wrap(['foo' => 'bar']);
Iteration:
foreach (IterableCollection::wrap(['foo' => 'bar']) as $key => $value) {
// use $key and $value
}
Check All True:
IterableCollection::wrap([true, false, true])->all();
# false
IterableCollection::wrap([true, true, true])->all();
# true
IterableCollection::wrap([1, 2, 'a'])->all('is_numeric');
# false
Check Any True:
IterableCollection::wrap([true, false, true])->any();
# true
IterableCollection::wrap(['a', 'b', 'c'])->any(fn ($i) => $i === 'd');
# false
Change Key Case:
$o = IterableCollection::wrap(['Hello' => 'World!']);
$o->changeKeyCase(CASE_LOWER);
# IterableCollection {
# hello: "World!",
# }
$o->changeKeyCase(CASE_UPPER);
# IterableCollection {
# HELLO: "World!",
# }
Chunk:
$o = IterableCollection::wrap(range(1,4));
// No preserve keys (default)
$o->chunk(2);
# IterableCollection {
# 0: [
# 1,
# 2,
# ],
# 1: [
# 3,
# 4,
# ],
# }
// Preserve keys
$o->chunk(2, true);
# IterableCollection {
# 0: [
# 0 => 1,
# 1 => 2,
# ],
# 1: [
# 2 => 3,
# 3 => 4,
# ],
# }
Column:
$o = IterableCollection::wrap([
['id' => 123, 'name' => 'Judah Wright',],
['id' => 456, 'name' => 'Jane Doe',],
]);
// Without column key (default)
$o->column('name');
# IterableCollection {
# 0: "Judah Wright",
# 1: "Jane Doe",
# }
// With a column key
$o->column('name', 'id');
# IterableCollection {
# 123: "Judah Wright",
# 456: "Jane Doe",
# }
Count:
IterableCollection::wrap([1, 2, 3])->count();
# 3
Combine:
$keys = ['foo', 'bing'];
$values = ['bar', 'baz'];
IterableCollection::wrap($keys)->combine($values);
# IterableCollection {
# foo: "bar",
# bing: "baz",
# }
Count Values:
IterableCollection::wrap(['foo', 'bar', 'foo', 'baz'])->countValues();
# IterableCollection {
# foo: 2,
# bar: 1,
# baz: 1,
# }
Fill Keys:
IterableCollection::wrap(['a', 'b', 'c'])->fillKeys('foo');
# IterableCollection {
# a: "foo",
# b: "foo",
# c: "foo",
# }
Filter:
$inputs = [true, false, null, "Hello!"];
// Without a callback (default) returns keeps the "truthy" values
IterableCollection::wrap($inputs)->filter();
# IterableCollection {
# 0: true,
# 3: "Hello!",
# }
// With a callback you can do your own evaluation
IterableCollection::wrap($inputs)->filter(
static fn ($value): bool => !is_null($value)
);
# IterableCollection {
# 0: true,
# 1: false,
# 3: "Hello!",
# }
Flip:
IterableCollection::wrap(['key' => 'value'])->flip();
# IterableCollection {
# value: "key",
# }
In:
$o = IterableCollection::wrap(['foo', 'bar']);
$o->in('foo');
# true
$o->in('baz');
# false
Key Exists:
$o = IterableCollection::wrap(['foo' => 'bar', 'bing' => 'baz']);
$o->keyExists('foo');
# true
$o->keyExists('asdf');
# false
Keys:
IterableCollection::wrap(['foo' => 'bar', 'bing' => 'baz'])->keys();
# IterableCollection {
# 0: "foo",
# 1: "bing",
# }
Map:
$o = IterableCollection::wrap(['John' => 'Smith', 'Jane' => 'Doe']);
$names = $o->map(
fn ($firstname, $lastname): string => "{$firstname} {$lastname}"
);
# IterableCollection {
# 0: "Smith John",
# 1: "Doe Jane",
# }
Reduce:
$o = IterableCollection::wrap([1, 2, 3]);
$o->reduce(static fn (int $carry, int $item): int => $carry + $item, 0);
# 6
To Array:
$iterator = new ArrayIterator(['foo' => 'bar']);
print_r(IterableCollection::wrap($iterator)->toArray());
# Array
# (
# [foo] => bar
# )
Values:
IterableCollection::wrap(['key1' => 'value1', 'key2' => 'value2'])->values();
# IterableCollection {#2519
# 0: "value1",
# 1: "value2",
# }
Walk Recursive:
$tree = [
'limb1' => [
'branch1' => 'leaf1',
'branch2' => 'leaf2',
],
'limb2' => 'leaf3'
];
IterableCollection::wrap($tree)->walkRecursive(
fn ($item, $key, $userdata) => "{$userdata} - {$key} - {$item}",
'tree',
);
# IterableCollection {
# 0: "tree - branch1 - leaf1",
# 1: "tree - branch2 - leaf2",
# 2: "tree - limb2 - leaf3",
# }
Walk:
$o = IterableCollection::wrap(['Bears', 'Beets', 'Battlestar Galactica']);
$o->walk(
function (&$item, &$key, int &$userdata): void {
$item = strtoupper($item);
$key = ['a', 'b', 'c'][$userdata];
$userdata++;
},
0,
);
# IterableCollection {
# a: "BEARS",
# b: "BEETS",
# c: "BATTLESTAR GALACTICA",
# }
Deliberately Excluded Functions
Items that would require the input to implement the Iterator class, such as:
Items that would require some form of indexing, ordering, or searching. These include:
- array_diff_assoc()
- array_diff_key()
- array_diff_uassoc()
- array_diff_ukey()
- array_diff()
- array_intersect_assoc()
- array_intersect_key()
- array_intersect_uassoc()
- array_intersect_ukey()
- array_intersect()
- array_merge()
- array_merge_recursive()
- arsort()
- asort()
- krsort()
- ksort()
- natcasesort()
- natsort()
Some functions responsible for creating a new list, such as: