Techno-magis

PHP et les tableaux à N dimensions

Monday 11th November 2013

Il n’est pas toujours évident de récupérer une valeur dans un tableau, surtout la profondeur est variable suivant tout un tas de paramètres. Je n’ai pas trouvé de méthode qui permet de lire, modifier ou tester l’existence d’une valeur dans un tableau dont le chemin est dynamique, type : $table[$keys[0]][$keys[1]]...[$keys[n]]. Pour ce faire, je me suis lancé dans la réalisation de trois méthodes pour arriver à cela.

La première fonction permet de récupérer une valeur du tableau :

CODE:

/**
 * Chercher une valeur dans un tableau multidimensionnel
 * @param array $table tableau à parcourir
 * @param multi $keys valeur ou tableau de parcours : $table[$keys[0]][$keys[1]]...[$keys[n]]
 * @param boolean $strict si activé, envoie une exception, sinon null en cas d'erreur (defaut = false)
 * @return la valeur ou null si la valeur n'est pas trouvée
 */
function array_get(&$table, $keys, $strict = false) {
	if (is_array($table)) {
		if (is_array($keys)) {
			$table_tmp = $table;
			$count = count($keys);
			while ($count > 0) {
				$count--;
				$key = array_shift($keys);
				if ($key != null && is_array($table_tmp) && array_key_exists($key, $table_tmp)) {
					if ($count == 0) {
						return $table_tmp[$key];
					} else {
						$table_tmp = $table_tmp[$key];
					}
				} else {
					if (!$strict) {
						return null;
					} else {
						throw new Exception("index {$key} requested does not exist");
					}
				}
			}
		} else if (isset($table[$keys]) && is_array($table[$keys])) {
			return $table[$keys];
		}
	}
	if (!$strict) {
		return null;
	} else {
		throw new Exception('Not an array');
	}
}

La fonction récursive suivante permet d’écrire dans le tableau :

CODE:

/**
 * Insérer une valeur dans un tableau multidimensionnel en créant si demandé les tableaux nécessaires pour
 * atteindre la position
 * @param array $table tableau à parcourir et modifier /!\
 * @param string|array[string] $keys valeur ou tableau de parcours : $table[$keys[0]][$keys[1]]...[$keys[n]]
 * @param mixed $val valeur à ajouter
 * @param boolean $creer créer le tableau s'il n'existe pas
 * @return true si réussi, false is échec
 */
function array_set(&$table, $keys, $val, $creer = true) {
	if (is_array($table)) {
		if (is_array($keys)) {
			if (count($keys) > 0) {
				$key = array_shift($keys);
 
				if (!isset($table[$key]) && $creer) {
					$table[$key] = array();
				}
				if (isset($table[$key])) {
					if (count($keys) == 0) {
						$table[$key] = $val;
						return true;
					} else {
						return array_set($table[$key], $keys, $val, $creer);
					}
				} else {
					return false;
				}
			}
 
		} else if (is_array($table[$keys])) {
			$table[$keys] = $val;
			return true;
		}
	}
	return false;
}

La dernière fonction test l’existence du chemin à travers les dimensions du tableau :

CODE:

/**
 * Tester l'existance une entrée dans un tableau multidimentionnel
 * @param array $table tableau à parcourir
 * @param multi $keys valeur ou tableau de parcours : $table[$keys[0]][$keys[1]]...[$keys[n]]
 * @return true si la valeur est trouvée
 */
function array_isset(&$table, $keys) {
	if (is_array($table)) {
		if (is_array($keys)) {
			$table_tmp = $table;
			$count = count($keys);
			while ($count > 0) {
				$key = array_shift($keys);
				if (isset($table_tmp[$key])) {
					if ($count == 1 && isset($table_tmp[$key])) {
						return true;
					} else if (!is_array($table_tmp[$key])) {
						return false;
					} else {
						$table_tmp = $table_tmp[$key];
					}
				} else {
					return false;
				}
				$count--;
			}
			return true;
		} else if (isset($table[$keys])) {
			return true;
		}
	}
	return false;
}

Si vous avez des remarques d'améliorations, je suis preneur. Même si c'est pour me dire que ça existe dans PHP et que je suis passé à côté.

Édit 18/10/2014 : Correction de bugs dans les algos... Je n'avais pas fait assez de tests. Cette fois j'ai une petite liste de tests unitaires dessus. Au passage, j'ai ajouté quelques plus.


Categories:
By Zéfling, the 11/11/2013 at 03:03:22
The ticket was read 347 times, with 0 comment posted.

No comment

Write your below.

Write a commentary