Conversione Array Multidimensionale a Array 2D (dot notation)

05 Mar 2020 | M.A.D.R.

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
/**
 * Copyright (c) 2020. Licenza Open Source - public domine
 * Il codice di questo file è reso disponibile secondo le regole vigente e con licenza d'uso PD.
 * Il codice riportato è un programma di cui codice sorgente è reso disponibile completo di tutte le sue
 * funzionalità e può essere modificato secondo le proprie esigenze.
 * Qualora il codice risultasse copiato su altri portali senza citarne la fonte saranno applicate tutte le
 * disposizioni in materia di Proprietà Intellettuale.
 */
/**
 * Created by phpS
 * User: Marco A.D.R.
 * Project Name: utils_git
 * File: ArrayDOTnotation.php
 * Path: ArrayDOTnotation
 * Date: 05/03/2020
 * Time: 08:08
 */
namespace Madi\DOT;

class ArrayDOTnotation {
	/**
	 * Array Input per conversione "DotNotation"
	 * @var array
	 */
	public $data=[];
	/**
	 * Risultato operazioni
	 * @var array
	 */
	public $result=[];
	/**
	 * Convert Array to 2D array w Dot Notation
	 * @param array $data
	 *
	 * @return array
	 */
	public static function array2Dot(array $data){
		return (new self($data))->arr2DOT()->result;
	}
	/**
	 * Convert 2D array to Multidimensional Array
	 * @param array $data
	 *
	 * @return array
	 */
	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);

Soluzioni complete per ogni esigenza