Collections#
ArrayKit collections provide an object-oriented array wrapper with:
dot-notation read/write
full
ArrayAccess+IteratorAggregate+Countablebehaviora chainable pipeline of transformation methods
optional get/set hooks via
HookedCollection
Available classes:
Infocyph\ArrayKit\Collection\CollectionInfocyph\ArrayKit\Collection\HookedCollectionInfocyph\ArrayKit\Collection\PipelineInfocyph\ArrayKit\Collection\LazyCollection
Creating Collections#
<?php
use Infocyph\ArrayKit\Collection\Collection;
use function Infocyph\ArrayKit\collect;
// Constructor
$c1 = new Collection(['a' => 1, 'b' => 2]);
// Static factories (accept array-able values)
$c2 = Collection::make(['x' => 10]);
$c3 = Collection::from(['y' => 20]);
// Namespaced helper (autoloaded by default)
$c4 = collect(['z' => 30]);
Reading and Writing#
Collection supports direct array access, dot notation, and helper methods.
<?php
use Infocyph\ArrayKit\Collection\Collection;
$c = new Collection([
'user' => ['name' => 'Alice'],
'active' => true,
]);
// Dot notation get/set
$name = $c->get('user.name'); // Alice
$c->set('user.email', '[email protected]');
// ArrayAccess with dot notation
$email = $c['user.email']; // [email protected]
$c['user.role'] = 'admin';
// Multi-key fetch
$subset = $c->get(['user.name', 'user.role']);
// Existence checks
$hasName = $c->has('user.name'); // true
$hasAny = $c->hasAny(['x', 'user.role']); // true
// Append with null offset
$c[] = 'tail-value';
// Remove key
unset($c['user.role']);
Collection Utility Methods#
<?php
use Infocyph\ArrayKit\Collection\Collection;
$c = new Collection(['a' => 1, 'b' => 2]);
$all = $c->all(); // full array
$items = $c->items(); // alias of all()
$keys = $c->keys(); // ['a', 'b']
$array = $c->toArray(); // array output
$json = $c->toJson(); // JSON string
$count = $c->count(); // 2
$empty = $c->isEmpty(); // false
$c->merge(['c' => 3]); // now a,b,c
$c->clear(); // now empty
// Immutable-style snapshots
$copy = $c->copy();
$immutable = $c->immutable();
Iteration and Interfaces#
Collection is directly iterable.
<?php
use Infocyph\ArrayKit\Collection\Collection;
$c = new Collection(['a' => 1, 'b' => 2]);
foreach ($c as $key => $value) {
// $key, $value
}
// Supports json_encode() through JsonSerializable
$json = json_encode($c);
HookedCollection#
HookedCollection extends Collection and adds per-key hooks.
<?php
use Infocyph\ArrayKit\Collection\HookedCollection;
$c = new HookedCollection(['name' => 'alice', 'user' => ['city' => 'dhaka']]);
// Run callback(s) when reading key
$c->onGet('name', fn ($v) => strtoupper((string) $v));
// Run callback(s) when setting key
$c->onSet('role', fn ($v) => "Role: $v");
// Dot-notation hooks are supported
$c->onGet('user.city', fn ($v) => ucfirst((string) $v));
echo $c['name']; // ALICE
$c['role'] = 'admin';
echo $c['role']; // Role: admin
echo $c['user.city']; // Dhaka
Pipeline Basics#
Every transformation method is exposed through Pipeline.
You can start it either with process() or directly by calling pipeline methods on collection (via __call).
Pipeline methods mutate the current collection instance and return that same instance for chaining.
Use copy() or immutable() before chaining when you need functional-style non-mutating behavior.
You can also force immutable-style pipeline entry using immutableProcess() / pipeImmutable().
<?php
use Infocyph\ArrayKit\Collection\Collection;
$c = Collection::make([1, 2, 3, 4, 5]);
// Dynamic passthrough to pipeline:
$result = $c->filter(fn ($v) => $v > 2)
->map(fn ($v) => $v * 10)
->all();
// Explicit pipeline:
$sum = $c->process()->sum();
Pipeline Methods by Category#
Selection and filtering:
only(),except()filter(),reject()where(),whereCallback()whereIn(),whereNotIn(),whereNull(),whereNotNull()between(),whereBetween()whereLike(),whereStartsWith(),whereEndsWith(),whereContains()firstWhere()firstWhereIn()
Slicing and positional:
slice(),skip(),skipWhile(),skipUntil()nth(),paginate(),chunk()
Structure and reshape:
flatten(),flattenByKey(),collapse()groupBy(),keyBy(),indexBy(),pluck(),transpose()mapWithKeys(),values(),rekey()wrap(),unWrap()
Ordering and uniqueness:
sortBy(),sortRecursive(),shuffle()sortByMany()unique(),duplicates(),uniqueBy(),duplicatesBy(),partition()intersect(),diff(),symmetricDiff(),same()
Terminal methods (end chain with scalar/array/bool):
sum(),min(),max(),first(),last(),reduce()any(),countBy(),median(),mode(),minBy(),maxBy(),isMultiDimensional()
Flow-control helpers:
tap(),pipe(),when(),unless()mergeRecursiveDistinct(),replaceRecursive(),overlay()
Detailed Pipeline Examples#
Filtering and set-style operations:
<?php
use Infocyph\ArrayKit\Collection\Collection;
$users = Collection::make([
['id' => 1, 'name' => 'Alice', 'role' => 'admin', 'age' => 30],
['id' => 2, 'name' => 'Bob', 'role' => 'editor', 'age' => 21],
['id' => 3, 'name' => 'Cara', 'role' => null, 'age' => 25],
]);
$admins = $users->where('role', 'admin')->all();
$notNullRole = $users->whereNotNull('role')->all();
$adultEditors = $users->where('age', '>=', 21)->whereIn('role', ['editor'])->all();
Slicing and paging:
<?php
use Infocyph\ArrayKit\Collection\Collection;
$list = Collection::make([10, 20, 30, 40, 50, 60]);
$page1 = $list->paginate(1, 2)->all(); // first 2 items
$everySecond = $list->nth(2)->all();
$skipped = $list->skip(3)->all();
$until40 = $list->skipUntil(fn ($v) => $v === 40)->all();
Grouping and reshaping:
<?php
use Infocyph\ArrayKit\Collection\Collection;
$rows = Collection::make([
['team' => 'A', 'score' => 10],
['team' => 'B', 'score' => 20],
['team' => 'A', 'score' => 30],
]);
$grouped = $rows->groupBy('team')->all();
$scores = $rows->pluck('score')->all(); // [10, 20, 30]
$sorted = $rows->sortBy('score', desc: true)->all();
$sortedMany = $rows->sortByMany([
['team', 'asc'],
['score', 'desc'],
])->all();
LazyCollection#
Use LazyCollection for generator-backed transformations over large iterables.
<?php
use Infocyph\ArrayKit\ArrayKit;
$result = ArrayKit::lazyCollection(range(1, 1000))
->filterLazy(fn ($v) => $v % 2 === 0)
->mapLazy(fn ($v) => $v * 10)
->take(5)
->all();
// [20, 40, 60, 80, 100]
Terminal calculations:
<?php
use Infocyph\ArrayKit\Collection\Collection;
$numbers = Collection::make([1, 2, 3, 4, 5]);
$sum = $numbers->process()->sum(); // 15
$median = $numbers->process()->median(); // 3
$mode = $numbers->process()->mode(); // [1,2,3,4,5] (all equal freq)
$hasEven = $numbers->process()->any(fn ($v) => $v % 2 === 0); // true
Behavior Notes#
Most pipeline methods return the underlying
Collectionfor chaining.Terminal methods return scalar/array/bool and stop the chain.
Dot-notation works in collection accessors and in
HookedCollectionget/set overrides.merge()follows PHParray_mergesemantics (string-key overwrite, numeric append/reindex).paginate()throwsInvalidArgumentExceptionwhenpage < 1orperPage < 1.flatten(0)keeps top-level values unchanged;flatten(1)flattens one level.sum()and numeric min/max flows ignore non-numeric values.