Come ben sappiamo gli array multidimensionali hanno una filosofia di memorizzazione “Bellissima”, flessibile e soprattutto di facile comprensione.
I problemi nascono quando abbiamo molti nested child in posizioni scomode, infatti basti pensare l’accesso all’elemento i-mo per recuperare il relativo valore.
Questa notazione come si diceva sopra seppur flessibile è insidiosa per chi alle prime armi non riesce ad ottimizzare il codice. Immaginiamo una struttura di questo tipo:
$array=
[
'name'=>'Pippo',
'surname'=>'Pluto',
'configs'=>[
'event-1'=>[
'show_profile'=>true,
'show_info'=>true,
'is_child'=>true,
'childs'=>[
'event-2'=>[
'show_profile'=>true,
'show_info'=>false,
'is_child'=>false,
'childs'=>[]
],
'event-3'=>[
'show_profile'=>true,
'show_info'=>false,
'is_child'=>true,
'childs'=>[
'event-7'=>[
'show_profile'=>false,
'show_info'=>false,
'is_child'=>true,
'childs'=>[
'event-2'
]
]
]
]
]
],
]
];
Seppur di semplice scrittura, il reperimento delle informazioni obbliga a creare “cicli” annidati per recuperare le informazioni.
Nel caso migliore possiamo ipotizzare di conoscere a priori la profondità massima dell’array e di conseguenza possiamo creare “N” cicli annidati con la nostra logica, cosa bene diversa è NON sapere la profondità massima del nostro array.
Una prima soluzione per i più smaliziati potrebbe essere la creazione di un metodo/funzione ricorsiva, ossia richiama se stessa nel momento in cui riconosce di avere un child.
Oggi appunto vediamo come convertire l’array di cui sopra in un “INI” o “DOT” notation.
La prima cosa da comprendere è che tutte le chiavi verranno convertite in stringa e i nested separati con il “DOT” ossia “PUNTO”, viceversa la funzione contraria, ossia da DOT a Multidimensionale.
Il risultato di sopra:
Array
(
[name] => Pippo
[surname] => Pluto
[configs.event-1.show_profile] => 1
[configs.event-1.show_info] => 1
[configs.event-1.is_child] => 1
[configs.event-1.childs.event-2.show_profile] => 1
[configs.event-1.childs.event-2.show_info] => [configs.event-1.childs.event-2.is_child] => [configs.event-1.childs.event-3.show_profile] => 1
[configs.event-1.childs.event-3.show_info] => [configs.event-1.childs.event-3.is_child] => 1
[configs.event-1.childs.event-3.childs.event-7.show_profile] => [configs.event-1.childs.event-3.childs.event-7.show_info] => [configs.event-1.childs.event-3.childs.event-7.is_child] => 1
[configs.event-1.childs.event-3.childs.event-7.childs.0] => event-2
)
Questo il risultato dell’array passato al nostro helper.
Codice:
<?php
namespace Madi\DOT;
class ArrayDOTnotation {
public $data=[];
public $result=[];
public static function array2Dot(array $data){
return (new self($data))->arr2DOT()->result;
}
public static function dot2Array(array $data){
return (new self())->dot2ARR($data)->result;
}
public function __construct(array $data=[]) {
(!empty($data))?$this->data=$data:null;
}
public function arr2DOT(){
$iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($this->data));
foreach ($iterator as $values) {
$keys=[];
foreach (range(0, $iterator->getDepth()) as $chd) {
$keys[] = $iterator->getSubIterator($chd)->key();
}
$this->result[ join( '.', $keys ) ] = $values;
}
return $this;
}
public function dot2ARR(array $input){
$t_data=[];
array_walk($input,function($v,$k) use (&$t_data){
$this->assignArrayByPath($t_data,$k,$v);
});
$this->result=$t_data;
return $this;
}
private function assignArrayByPath(&$array, $where, $value, $separator='.') {
$keys = explode($separator, $where);
foreach ($keys as $key) {
$array = &$array[$key];
}
$array = $value;
}
}
Per richiamare la nostra classe possiamo operare attraverso i metodi statici rispettivamente:
- array2Dot
- Converte un qualsiasi array in 2D
- dot2Array
- Converte array 2D in array multidimensionale
La chiamata alle funzioni risulta semplice una volta inclusa la class e la si può eseguire in questo modo
$dot=\Madi\DOT\ArrayDOTnotation::array2Dot($array);
$multi=\Madi\DOT\ArrayDOTnotation::dot2Array($dot);