Index
# Array Function in the namespace `MMO\core\arrays\...` are used to interact with array or array like values: - Classes that are iterable (implementing <@\Iterator> or <@\IteratorAggregate>) - Classes that can be accessed like array (implementing <@\ArrayAccess>) ## Get Started ## Array path In nested array, we often wants to access a sub value : `$a[0][1][..]`. This access can be written as a json path `0/1/..`. [!Note]: for key containing `/`, you need to escape them as `~1` or call function <@\MMO\core\paths\escape>. ### Walking to a nested value To get to a nested value you can use the function <@\MMO\core\arrays\walk>. It **yields** an array of values for each step of the process. [!WARNING] if a nested value does not exist along the walk, a <@\MMO\core\exceptions\eNotFound> is thrown. ```php $a = ['A' => [1,2]]; foreach (\MMO\core\arrays\walk($a, 'A/0') as $info) { list($value, $key, &$parent) = $info; //$value is the current value //$key is the current key //$parent is the current parent given by reference ($parent[$key] === $value) } ``` For any function that uses array walking, you can tell if you want the inner structure to be created. Array are used to create the inner structure. ### Getting a nested value ```php $a = ['A' => [1,2]]; $x = \MMO\core\arrays\get($a, 'A/1'); //$x = 2 $x = \MMO\core\arrays\get($a, 'A/55'); //> throw eItemNotFound ``` To get a default value, pass it as third argument ```php $x = \MMO\core\arrays\get($a, 'A/55', 'nothing'); //$x = 'nothing' ``` ### Setting a nested value The `set` function returns a boolean indicating if the value has changed. ```php $a = ['A' => [1,2]]; \MMO\core\arrays\set($a, 'A/1', 66);//true //$a = {A: [1,66]} \MMO\core\arrays\set($a, 'A/1', 66);//false //set a value in a new part of $a (won't trigger an eNotFound) \MMO\core\arrays\set($a, 'B/0', 99);//true //$a = {A:[1,66], B:[99]} ``` ### Pushing a nested value The `push` function returns the array in which the value has been pushed. If the value at the given path is not an array, it is automatically converted to an array. ```php $a = ['A' => [1,2]]; \MMO\core\arrays\push($a, 'A', 3);//&$a['A'] //$a = {A: [1,2,3]} \MMO\core\arrays\push($a, 'B', 66);//&$a['B'] //$a = {A: [1,2,3], B: [66]} ``` ### Deleting a nested value The `delete` function returns a boolean indicating if the value has changed. This function is safe for list. It uses: - `unset` on array object - `array_splice` on array list - `offsetUnset` on object ## Array properties - Class can declare array properties with the class attribute <@\MMO\core\attributes\ArrayProperty>. - The class needs to implement <@\MMO\core\interfaces\iArrayProperties> and use the trait <\MMO\core\classes\tArrayProperties>. ```php #[\MMO\core\attributes\ArrayProperty(name: 'x', getter: '$x', setter: '$x')] class MyObject implements \MMO\core\interfaces\iArrayProperties { use \MMO\core\classes\tArrayProperties; protected $x; } $e = new MyObject(); $e['x'] = [0,1]; $e['x'][1] = 66; \MMO\dump($e['x']); //[0,66] ``` - You can access the properties using the static function `ArrayProperties(): array` - You can access a specific property using the static function `ArrayProperty(string $key): ArrayProperty` ### Getter / Setter Each array property is read using the `attribute->getter` and written using the `attribute->setter`. Values can be : - If the attribute is null, the value can't be read (getter) or written (setter). - If the attribute is `$xxx`, the property `xxx` is used. Public, protected and private properties are supported. - Else the method of the object is called: - getter: `public function(): mixed` - setter: `public function(mixed $value): void` ## Array merging The php function `array_merge` has a weird behavior. It is not recursive, and it does not treat list and map the same way. To correct these problems, the function <@\MMO\core\arrays\merge> has been created. It is recursive, and you can define if you want your lists to be appended or merged like the maps. [!WARNING] if you pass an array in this function, it won't be changed. But if you pass an object implementing ArrayAccess, this object will be changed. If you do not want this to happen, clone the object before merging the values. ## Array injection In order to give more options to the merging process, you can use <@\MMO\core\arrays\inject>. Every key of the injected array can start with a specific special char, that alters the merging process: - `?xxx`: the value is merged only if it does not exist in the source - `=xxx`: the value is set instead of being merged if a key starts either with `?` or `=` and should not be treated a an injection, escape it with `\ `. ### List behavior The injection is recursive and lists are not appended to each other. They are treated like maps. ```php \MMO\core\arrays\inject(['a' => [0,1,2]], ['a' => [3,4]]);// {a: [3,4,2]} \MMO\core\arrays\inject(['a' => [0,1,2]], ['=a' => [3,4]]);// {a: [3,4]} ``` In order to append a list to another, you can use the special value `$[..]`. It will be replaced by the old values in the source. ```php \MMO\core\arrays\inject(['a' => [0,1]], ['a' => ['$[..]',2,3]]);// {a: [0,1,2,3]} \MMO\core\arrays\inject(['a' => [0,1]], ['a' => [-1,'$[..]',2]]);// {a: [-1,0,1,2]} ``` Because list cannot have keys, you can also define a 'unique' behavior by writing this: ```php \MMO\core\arrays\inject(['a' => [0,1]], ['?a' => ['$[..]',1,2]]);// {a: [0,1,2]} //notice the difference (1 is repeated) \MMO\core\arrays\inject(['a' => [0,1]], ['a' => ['$[..]',1,2]]);// {a: [0,1,1,2]} ``` [!NOTE] a simple way to get rid of the special chars in an array, use inject with an empty array as source: `\MMO\core\arrays\inject([], $config)` [!WARNING] if you pass an array in this function, it won't be changed. But if you pass an object implementing ArrayAccess, this object will be changed. If you do not want this to happen, clone the object before merging the values. ## References ### See also ## Tags <#array>, <#property>, <#attribute>