Index

MMO\core\arrays

MMO\core\arrays · 21 symbols · generated 5 Oct 2026

function

count

arrays.php:454

Get the number of elements in any iterable (not just a plain array/\Countable) -- for a plain \Iterator without \Countable, this has to fully traverse it (there's no shortcut).

function count(Traversable|Countable|array $array): int
Namespace
MMO\core\arrays
$arrayTraversable | Countable | array
returnsint
count(['a' => 1, 'b' => 2, 'c' => 3]); // 3
Call graph
function

delete

arrays.php:289

Delete the value at the given json-path. If the immediate parent is a list (sequential int keys), the item is spliced out (so later items shift down); otherwise the key is just unset. Any iMutationObserver walked along the path is notified (mutate('-', ...)), innermost first. A missing path is silently a no-op.

function delete(ArrayAccess|array &$src, array|string $path): mixed
Namespace
MMO\core\arrays
$srcArrayAccess | array
$patharray | stringa json-path string, or an already-split array of segments
returnsmixedthe value that was removed, or null if $path didn't exist
$data = ['a' => ['b' => 1, 'c' => 2]]; delete($data, 'a/b'); // returns 1, $data becomes ['a' => ['c' => 2]]
Call graph
function

diff

arrays.php:475

Get the elements of $a whose value is not (strictly) present anywhere in $b -- like \array_diff(), but using strict (===) comparison instead of string-casting comparison, so it works correctly with non-scalar values too. $a's keys are preserved.

function diff(array $a, array $b): array
Namespace
MMO\core\arrays
$aarray
$barray
returnsarray
diff(['one' => 1, 'two' => 2, 'three' => 3], ['one' => 1]); // ['two' => 2, 'three' => 3]
function

exists

arrays.php:222

Tells if a value exists at the given json-path (without fetching it).

function exists(ArrayAccess|array $src, array|string $path): bool
Namespace
MMO\core\arrays
$srcArrayAccess | array
$patharray | string
returnsbool
exists(['a' => ['b' => 1]], 'a/b'); // trueexists(['a' => ['b' => 1]], 'a/nope'); // false
Call graph

Uses (1)

Used by (1)

function

filterKeys

arrays.php:94

Filter (and, in select mode, reorder) an array's keys recursively.

function filterKeys(array $data, array $fields, string $path = ''): array
Namespace
MMO\core\arrays
There are only two strategies, auto-detected from $fields: `select` (keep and order ONLY the keys marked true) or `remove` (keep everything except the keys marked false, in their original order). If ANY field is marked visible (true), select mode wins entirely -- fields marked false are then simply irrelevant/ignored, they don't additionally exclude anything (select is dominant over remove).
$dataarraythe data to filter
$fieldsarray{path} => {visibility} (a nested path uses /, e.g. 'b/b')
$path = ''stringthe current path in the data (internal, for the recursive call). MUST end with / if not empty.
returnsarray
filterKeys(['a' => 1, 'b' => 2, 'c' => 3], ['b' => true, 'a' => true]); // ['b' => 2, 'a' => 1] (select, and reordered) filterKeys(['a' => 1, 'b' => 2, 'c' => 3], ['b' => false]); // ['a' => 1, 'c' => 3] (remove, order kept) filterKeys(['a' => 1, 'b' => ['a' => 'b1', 'b' => 'b2']], ['a' => false, 'b/b' => true]); // ['b' => ['b' => 'b2']]
Call graph

Uses (1)

Used by (1)

function

from

arrays.php:33

Convert any value into a plain array: an \MMO\core\interfaces\iArray is unwrapped via toArray(), a Generator/Traversable is consumed via \iterator_to_array(), a plain array is returned as-is, and anything else is wrapped as a single-element array (if $force) or rejected.

function from(mixed $array, bool $force = true, ?bool $preserveKeys = null): array
Namespace
MMO\core\arrays
See
https://www.php.net/manual/en/language.generators.syntax.php)
$arraymixed
$force = trueboolif true (default), a value that isn't array-like is wrapped as [$array] instead of throwing
$preserveKeys = nullnull | boolonly used when $array is a Generator/Traversable. WARNING: only set this to true when yielding WITH explicit keys. Otherwise values may be lost, since consecutive yields would share the same auto-incremented keys (this is why Generator defaults to false here but a plain Traversable defaults to true --
returnsarray
throwsif the value cannot be converted and $force is false
from([1, 2, 3]); // [1, 2, 3] (unchanged) from('scalar'); // ['scalar'] ($force defaults true) from('scalar', false); // throws eInvalid
Call graph

Used by (1)

function

get

arrays.php:202

Get a value at the given json-path.

function get(ArrayAccess|array $src, array|string $path, mixed $default = null): mixed
Namespace
MMO\core\arrays
NOTE: a missing LEAF just returns $default (or null): 'a' in `[]` returns null/$default. But a missing INTERMEDIATE segment throws: 'a/b' in `[]` throws for 'b', since there's no array at 'a' to look 'b' up in. WARNING: if $default is not explicitly passed AND the path doesn't exist, an eItemNotFound IS thrown even for the simple missing-leaf case above (the exact opposite of the note's first sentence) -- this function detects "was $default passed?" via func_num_args(), so it behaves differently depending on whether you wrote `get($src, $path)` or `get($src, $path, null)`, even though both look like "no default".
$srcArrayAccess | array
$patharray | string
$default = nullmixedreturned when $path (or its leaf) doesn't exist -- but see the WARNING above
returnsmixed
throwswhen a path parent cannot be accessed, or (if $default wasn't passed at all) when the leaf doesn't exist either
get(['a' => ['b' => 1]], 'a/b'); // 1 get(['a' => 1], 'x', 'fallback'); // 'fallback' -- default explicitly given get([], 'a/b'); // throws eItemNotFound -- no default given at all
Call graph
function

inject

arrays.php:575

Inject a configuration into $src recursively: every key of $config is itself a json-path into $src, and its value is set() (recursively merge()d with whatever's already there, by default) at that path.

function inject(ArrayAccess|array &$src, iterable $config, bool $recursive = true): void
Namespace
MMO\core\arrays
A path can start with a special character that alters how that one entry is injected: - `?xxx`: only inject if nothing already exists at path 'xxx' (existing data wins) - `=xxx`: inject at path 'xxx' WITHOUT recursing (replace outright, even if both sides are arrays) - `\?xxx`/`\=xxx`: escapes a path that's genuinely meant to start with a literal `?`/`=` character A list value (sequential int keys) containing the literal string `'$[..]'` has that placeholder replaced by the list already present at that path -- e.g. `['a' => [-1, '$[..]', 2]]` prepends -1 and appends 2 to whatever list 'a' already had; combined with `?`, this is also how you de-duplicate while merging (`['?a' => [0, '$[..]', 1]]` keeps the old list's own values unique against the new ones). $data2 = ['a' => [0, 1]]; inject($data2, ['a' => [-1, '$[..]', 2]]); // $data2 becomes ['a' => [-1, 0, 1, 2]] $data3 = ['a' => [0, 1]]; inject($data3, ['?a' => [2, 3]]); // $data3 stays ['a' => [0, 1]] -- 'a' already existed, '?' skips it
$srcArrayAccess | array
$configiterablethe configuration to inject into $src
$recursive = trueboolif false, every entry replaces outright instead of merging (like a global = prefix)
returnsvoid
$data = ['a' => ['b' => 1]]; inject($data, ['a' => ['c' => 2]]); // $data becomes ['a' => ['b' => 1, 'c' => 2]] (merged)
Call graph
function

isUnique

arrays.php:694

Tells if every value in $array is distinct (strict, ===, comparison).

function isUnique(array $array): bool
Namespace
MMO\core\arrays
$arrayarray
returnsbool
isUnique(['a' => 1, 'b' => 2]); // true isUnique(['a' => 1, 'b' => 1]); // false
Call graph
function

keys

arrays.php:431

Get the keys of any iterable (not just a plain array) as a plain array.

function keys(iterable $array): array
Namespace
MMO\core\arrays
$arrayiterable
returnsarray
throwsif $array is an iArray/array/IteratorAggregate/Iterator none of the above
keys(['one' => 1, 'two' => 2]); // ['one', 'two']
function

matchMask

arrays.php:500
Test each key present in $mask against the corresponding key in $value. Only keys present in $mask are tested (extra keys in $value are ignored). Each mask entry can be: - an iSchema: $value[$key] is coerced then validated against it (missing/invalid becomes the schema's default, unless the schema itself marks the property required, in which case that fails the match) - a string: matched as a moustache template ([`matchTemplate()`](https://mcp.mmoframework.fr/documentation/mmo.core/php/strings.md#matchtemplate)) against the value cast to string -- except when the value is itself an array (e.g. a repeated query parameter), where the string must instead be a bare `{key}` placeholder matching this exact key, and the whole array is captured as-is - anything else: matched for strict equalityfunction matchMask( array $mask, ArrayAccess|array $value, ?array &$matches = null, ?array $schemas = null ): string|true
Namespace
MMO\core\arrays
$maskarray
$valueArrayAccess | array
$matches = nullnull | array
$schemas = nullnull | arraya list of schemas to use for the type in placeholders. if null, use the global schemas
returnsstring | truetrue if it matches, else the mask key that failed
matchMask(['id' => '{id:integer}'], ['id' => '42'], $matches); // true, $matches = ['id' => 42] matchMask(['status' => 'active'], ['status' => 'inactive']); // 'status' -- the failing key
Call graph
function

merge

arrays.php:388

Recursively merge $value into $src: for matching keys whose values are themselves both array-like, merge recursively; otherwise $value's value simply overwrites $src's. Two plain lists (sequential int keys) are concatenated (if $appendList) rather than merged key-by-key -- otherwise merging [1,2,3] with [9] would overwrite index 0 instead of appending. Notifies iMutationObserver::mutate('=', ...) for every value actually changed, if $src implements it.

function merge(ArrayAccess|array $src, iterable $value, bool $appendList = true): ArrayAccess|array
Namespace
MMO\core\arrays
$srcArrayAccess | arraysource value (NOT modified if it's a plain array; IS modified in place if it's an ArrayAccess, since arrays are always copied on write but objects aren't)
$valueiterablethe data to merge into $src
$appendList = trueboolif false, two lists are merged key-by-key (index 0 with index 0, ...) instead of concatenated
returnsArrayAccess | arrayis array ? array<mixed> : ArrayAccess<mixed, mixed>) $src, merged (the same kind it was given)
merge(['one' => 1], ['two' => 2, 'one' => 11]); // ['one' => 11, 'two' => 2] merge(['one' => [1]], ['one' => [11]]); // ['one' => [1, 11]] -- nested lists are concatenated merge([1, 2, 3], [9]); // [1, 2, 3, 9]
Call graph
function

mergeAt

arrays.php:419

Same as merge(), but merges $value into whatever is already at $path (instead of into $src itself), then writes the result back with set().

function mergeAt( ArrayAccess|array &$src, string $path, mixed $value, bool $appendList = true ): void
Namespace
MMO\core\arrays
$srcArrayAccess | array
$pathstringa json-path
$valuemixedthe data to merge in at $path
$appendList = trueboolmerge()
returnsvoid
$data = ['a' => ['x' => 1]]; mergeAt($data, 'a', ['y' => 2]); // $data becomes ['a' => ['x' => 1, 'y' => 2]]
Call graph

Uses (3)

function

mergeInject

arrays.php:636

A shallow, synchronous cousin of inject(): recursively merge $config into $src and return the result (rather than mutating a reference and honoring the ?/= path-prefix directives), understanding the same $[..] list-splicing placeholder. Useful to pre-merge several config sources into one plain array before actually applying it (e.g. with inject() or set()) later.

function mergeInject(array $src, array $config): array
Namespace
MMO\core\arrays
$srcarray
$configarray
returnsarray
mergeInject(['a' => ['x' => 1]], ['a' => ['y' => 2]]); // ['a' => ['x' => 1, 'y' => 2]]
Call graph
function

options

arrays.php:51

The options array behind $options: a typed options object (iOptions) gives its toArray(), an array is returned as it is. What accepts both calls this first.

function options(MMO\core\interfaces\iOptions|array $options): array
Namespace
MMO\core\arrays
$optionsiOptions | array
returnsarraymixed>
options(new \MMO\core\printers\PrintOptions(escape: true)); // ['escape' => true]options(['escape' => true]); // ['escape' => true]
Call graph
function

push

arrays.php:335

Append a value to the list at the given json-path (turning a non-list scalar/null already there into a single-element list first, so it can be appended to). Any iMutationObserver walked along the path is notified (mutate('+', ...)), innermost first.

function push( ArrayAccess|array &$src, array|string $path, mixed $value, bool $unique = false, bool $create = true ): ArrayAccess|array
Namespace
MMO\core\arrays
$srcArrayAccess | array
$patharray | stringa json-path string, or an already-split array of segments
$valuemixedthe value to push
$unique = falseboolif true, don't push if $value is already present (strict comparison)
$create = trueboolif false, don't create missing intermediate path items (walk())
returnsArrayAccess | arraya reference to the list $value was pushed into (or would have been, if $unique skipped it), so the caller can keep working with it directly
$data = []; push($data, 'list', 'v1'); push($data, 'list', 'v2'); // $data becomes ['list' => ['v1', 'v2']]
Call graph
function

set

arrays.php:253

Set a value at the given json-path, creating missing intermediate arrays by default.

function set( ArrayAccess|array &$src, array|string $path, mixed $value, bool $create = true ): void
Namespace
MMO\core\arrays
Every object walked along the path that implements iMutationObserver has its mutate('=', ...) called (innermost first), so e.g. a Schema/Container can react to (or veto, by returning true) a change anywhere inside it. A no-op (value already identical, `!==` compared) skips the write and the notifications entirely.
$srcArrayAccess | array
$patharray | stringa json-path string, or an already-split array of segments
$valuemixedthe value to set
$create = trueboolif true (default), a missing intermediate array along the path is created
returnsvoid
throwsif $path is empty (there's nothing to assign the value to)
$data = []; set($data, 'a/b', 1); // $data becomes ['a' => ['b' => 1]]
Call graph
function

sortPreserve

arrays.php:69

Sort an array in place using $sortFn, like \uasort()/\uksort(), but stable: when two items are equivalent ($sortFn returns 0), their original relative order is preserved instead of being left unspecified.

function sortPreserve( array &$array, callable $sortFn, bool $reverse = false, bool $byKeys = false ): void
Namespace
MMO\core\arrays
NOTE: if $array was a list (sequential int keys), it is re-indexed back into one after sorting.
$arrayarray
$sortFncallablea comparator: function(mixed $a, mixed $b): int, called with values (or, if $byKeys, with keys) from $array
$reverse = falseboolif true, ties ($sortFn returns 0) are ordered by REVERSE original order instead of original order
$byKeys = falseboolif true, $sortFn receives the two KEYS being compared instead of their values
returnsvoid
$a = ['c' => 3, 'a' => 1, 'b' => 2]; sortPreserve($a, fn($x, $y) => $x <=> $y); // $a becomes ['a' => 1, 'b' => 2, 'c' => 3]
Call graph
function

uniqueList

arrays.php:660

Merge one or more iterables and keep only the first occurrence of each (strictly, ===) distinct value, re-indexed as a plain list (original keys are discarded).

function uniqueList(iterable ...$arrays): array
Namespace
MMO\core\arrays
...$arraysiterable
returnsarray
uniqueList([5 => 4, 1 => -1, 6 => 5, 10 => 9, 's' => 'last']); // [4, -1, 5, 9, 'last']
Call graph
function

uniqueMap

arrays.php:676

Same as uniqueList(), but preserves the (first-seen) key of each distinct value instead of re-indexing.

function uniqueMap(iterable ...$arrays): array
Namespace
MMO\core\arrays
...$arraysiterable
returnsarray
uniqueMap(['a' => 1, 'b' => 2, 'c' => 2]); // ['a' => 1, 'b' => 2] -- 'c' dropped, value 2 already kept under 'b'
function

walk

arrays.php:155

The low-level primitive get()/exists()/set()/delete()/push() are all built on: walk down a json-path (/-separated, RFC-6902-escaped -- split()) through nested arrays/ArrayAccess objects, yielding each step so the caller can inspect or mutate it along the way.

function walk(ArrayAccess|array &$src, array|string $path, bool $create = false): Generator
Namespace
MMO\core\arrays
$srcArrayAccess | array
$patharray | stringa json-path string, or an already-split array of segments
$create = falseboolif true, a missing intermediate array along the path is created (as []) instead of making the walk stop early
returnsGeneratormust be consumed with foreach
throwsif a non-final path segment leads into something that isn't an array/ArrayAccess (and $create didn't apply, e.g. because it's not null but some other scalar)
$info = null; foreach (walk($data, 'a/b') as $info) {...} // 2 yields: one for 'a', one for 'b' $info[2][$info[1]] = 'new value'; // writes $data['a']['b'], via the reference captured in $info[2]
Call graph