loader

Conversione Array Multidimensionale a Array 2D (dot notation)

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);