Récursivité : afficher toutes les clés et valeurs d’un objet ou tableau multidimensionnel en PHP

Mathieu Chartier 6 septembre 2018 à 15:56 Tutoriels vidéo 2 commentaires

Cela faisait si longtemps que je voulais présenter des exemples de récursivité (ou "récursion") que je profite de ce tutoriel vidéo pour vous en montrer un exemple fort pratique et intéressant en PHP : le parcours et l'affichage de l'ensemble des données d'un tableau à "n" dimensions, et quel que soit le type de valeur qu'il contient (objet, chaîne de caractère, booléen et numérique par exemple).

Qu'est-ce que la récursivité ?

La récursivité est un principe de programmation qui vise à utiliser en boucle une même fonction jusqu'à ce qu'une issue favorable soit trouvée. Le cas le plus connu est sûrement la suite de Fibonacci pour laquelle chaque nombre de la suite est la somme des deux nombres précédents. En d'autres termes, la récursivité appelle dans une fonction cette même fonction, et ainsi de suite.

En effet, il arrive fréquemment de devoir parcourir les clés et valeurs de tableaux multidimensionnels (ou objets) à "n" dimensions pour retrouver des données spécifiques. Mais force est de constater que de faire des foreach dans des foreach peut très vite devenir barbant, et encore plus quand on ne sait pas combien de niveaux il faudra parcourir exactement.. C'est là tout l'enjeu de la récursivité ! ;-)

Introduction à la récursivité (récursion) en PHP avec des objets et tableaux multidimensionnels à parcourir

Alors, quoi de mieux qu'une fonction du type print_r() qui parcoure tous les niveaux de profondeur d'un tableau avec un affichage personnalisable ? L'idée est ici de pouvoir parcourir n'importe quel tableau ou objet PHP, quel que soit son niveau de profondeur, en remontant à chaque fois les clés et valeurs qui nous intéressent. Ainsi, l'affichage est plus lisible (enfin si on ne fait pas n'importe quoi ^^) qu'un print_r() ou un var_dump(). Ajoutons à cela que les fonctions que nous allons étudier vont automatiquement masquer les clés privées (private) et protégées (protected) en cas de parcours d'un objet, il ne restera donc que les valeurs utiles et publiques !

Quand le nombre de dimensions devient pharaonique...

Pour l'anecdote, j'utilise parfois les fonctions présentées ici (voir codes dans la conclusion ou dans la vidéo) quand j'utilise des API comme celles de Google ou de Twitter. Cela me permet rapidement de trouver les données qui m'intéressent, ou tout simplement de pouvoir rapidement rejoindre un niveau de profondeur donné. Voyez donc cela comme des fonctions permettant un gain de temps à l'usage, bien qu'on puisse s'en sortir avec des print_r() ou des var_dump() bien entendu dans la majorité des cas peu profonds.

Je vous invite donc à regarder la vidéo ou à passer directement à la conclusion pour retrouver les codes de 3 fonctions PHP permettent le parcours rapide de tableaux multidimensionnels :

  • print_recursive() : fonction simple qui affiche toutes les clés => valeurs sur plusieurs niveaux de profondeur. C'est une sorte de print_r() avec un affichage plus simple et personnalisable si besoin (en changeant dans la fonction).
  • print_recursive_tab() : même fonction si ce n'est qu'elle permet aussi de retourner un tableau pour chaque niveau de profondeur. Plus l'indice du tableau retourné est élevé, plus vous êtes dans les niveaux profonds. Cette fonction est surtout utile pour trouver des données parfois cachés à une dizaine de niveaux de profondeur (dans les API notamment, cela peut arriver).
  • print_recursive_callback() : fonction qui permet d'appeler une fonction de rappel (callback) pour personnaliser l'affichage des données lors du parcours du tableau. C'est en théorie la fonction la plus pratique pour obtenir un résultat souhaitable.
Tutoriel vidéo - Récursivité : afficher toutes les clés et valeurs d’un objet ou tableau multidimensionnel en PHP

Conclusion

J'espère que la vidéo vous a éclairé quelque peu sur l'usage des 3 fonctions d'affichage d'objets ou de tableaux multidimensionnels avec l'ensemble des clés et valeurs. Sans plus attendre, vous pouvez télécharger le fichier suivant qui contient les fonctions ainsi que l'exemple présenté dans la vidéo. Et si vous préférez, vous pouvez copier/coller chacune des fonctions ci-dessous.

Télécharger “3 fonctions print_recursive en PHP [Zip]”print_recursive.zip – Téléchargé 91 fois – 2 KB

print_recursive

La fonction print_recursive() prend jusqu'à 3 paramètres :

  1. le tableau ou objet PHP à parcourir et lire ;
  2. la mise en gras ou non des clés de tableaux (pour faciliter la lecture), via un booléen (true/false) ;
  3. le numéro de niveau de profondeur (normalement, laissez tel quel).
function print_recursive($tab = array(), $strong = false, $niveau = 0) {
	// Supprime les clés private et protected s'il s'agit d'un objet
	if(is_object($tab)) {
		$tab = get_object_vars($tab);
	}

	// Ajoute les sauts de ligne pour chaque niveau de profondeur (sauf le premier !)
	if($niveau != 0) {
		echo "<br/>";
	}

	foreach($tab as $key => $value) {
		// Affichage des clés avec tabulation par niveau de profondeur
		if($strong === true) {
				echo str_repeat("&nbsp;", $niveau * 4)."<strong>".$key."</strong> => ";
			} else {
				echo str_repeat("&nbsp;", $niveau * 4).$key." => ";
			}

		// Vérifie si la valeur correspond elle-même à un tableau ou un objet
		if((is_array($value) || is_object($value))) {
			// Appel récursif de la fonction pour lire un autre niveau de profondeur
			print_recursive($value, $strong, $niveau + 1);
			continue;
		}

		// Affichage des valeurs (quand ce ne sont pas des tableaux/objets)
		echo $value."<br/>";
	}
}
print_recursive_tab

La fonction print_recursive_tab() retourne un tableau complet pour chaque niveau de profondeur du tableau. Plus vous ciblez un indice haut, plus vous obtenez des clés et valeurs d'une certaine profondeur. La fonction PHP prend jusqu'à 4 paramètres :

  1. le tableau ou objet PHP à parcourir et lire ;
  2. l'affichage ou non des données (comme la fonction print_recursive), via un booléen (true/false) ;
  3. la mise en gras ou non des clés de tableaux (pour faciliter la lecture), via un booléen (true/false) ;
  4. le numéro de niveau de profondeur (normalement, laissez tel quel).
function print_recursive_tab($tab = array(), $echo = false, $strong = false, $niveau = 0) {
	// Crée un tableau statique pour enregistrer chaque niveau de profondeur
	static $new_tab = array();

	// Ajoute les sauts de ligne pour chaque niveau de profondeur (sauf le premier !)
	if($echo === true && $niveau != 0) {
		echo "<br/>";
	}

	foreach($tab as $key => $value) {
		if($echo == true) {
			// Affichage des clés avec tabulation par niveau de profondeur
			if($strong === true) {
				echo str_repeat("&nbsp;", $niveau * 4)."<strong>".$key."</strong> => ";
			} else {
				echo str_repeat("&nbsp;", $niveau * 4).$key." => ";
			}
		}

		// Enregistre les données niveau de profondeur par niveau de profondeur
		if(!is_object($value)) {
			$new_tab[$niveau][$key] = $value;
		} else {
			$new_tab[$niveau][$key] = get_object_vars($value);
		}

		if((is_array($value) || is_object($value))) {
			// Appel récursif de la fonction pour lire un autre niveau de profondeur
			print_recursive_tab($value, $echo, $strong, $niveau + 1);
			continue;
		}
		
		if($echo == true) {
			// Affichage des valeurs (quand ce ne sont pas des tableaux/objets)
			echo $value."<br/>";
		}
	}

	// Retourne le tableau pour chaque niveau de profondeur
	return $new_tab;
}
print_recursive_callback

La fonction print_recursive_callback() permet de personnaliser l'affichage des résultats grâce à une fonction de rappel (callback). Bien sûr, vous n'avez pas une pleine liberté à cause de la récursivité de la fonction (qui empêche d'effectuer certains rendus), mais cela permet vraiment d'obtenir un résultat différent, comme le montrera la capture suivante basé sur l'exemple de la vidéo. La fonction PHP peut prendre jusqu'à 4 paramètres :

  1. le tableau ou objet PHP à parcourir et lire ;
  2. la fonction de rappel (callback) ;
  3. l'affichage ou non des clés de premiers niveaux (true/false) ;
  4. le numéro de niveau de profondeur (normalement, laissez tel quel).
function print_recursive_callback($tab = array(), $callback, $withKey = true, $niveau = 0) {
	// Supprime les clés private et protected s'il s'agit d'un objet
	if(is_object($tab)) {
		$tab = get_object_vars($tab);
	}

	foreach($tab as $key => $value) {
		if((is_array($value) || is_object($value))) {
			// Appel récursif de la fonction pour lire un autre niveau de profondeur
			if($withKey === true) {
				call_user_func($callback, $key, "", $niveau);
			}
			print_recursive_callback($value, $callback, $withKey, $niveau + 1);
			continue;
		}

		// Appel à la fonction de rappel avec quatre paramètres oblibatoires !!!
		if($withKey === true) {
			call_user_func($callback, $key, $value, $niveau);
		} else {
			call_user_func($callback, $key, $value, $niveau);
		}
	}
}

Comparer les fonctions de lecture des objets et tableaux en PHP

Observez la capture finale ci-dessous qui affiche le même tableau multidimensionnel (contenant des objets) selon les fonctions utilisées. Cela élargit la panoplie des possibilités et permet de plus facilement parcourir les données en PHP, sans forcément faire appel au classique print_r() à qui il faut adjoindre des balises "pre" en HTML, ou à var_dump() parfois illisible quand la profondeur du tableau est vaste.

Afficher ou parcourir un objet ou tableau multidimensionnel en PHP avec clé et valeur

2 commentaires

  • FRANCOIS LEMOINE dit :

    Bonjour,

    Un grand merci pour ce billet et les exemples (qui fonctionnent !). C'est exactement ce que je cherchais. Novice en PHP je me battais avec le décodage de fichiers Json provenant d'une API (celle de la DILA de Legifrance) avec des tableaux jusqu'à 7 ou 10 niveaux.
    Deux petites questions si vous me permettez :
    - est-il possible de ne sélectionner que certaines clés/valeur en faisant un test sur le nom de la clé ? et/ou sur le niveau de profondeur ?
    - j'ai lu également votre billet ( https://blog.internet-formation.fr/2014/07/parser-les-publications-facebook-avec-curl-et-simplexml-en-php/). Est-ce la bonne voie pour parser un tableau multidimensionnel et en faire un flux RSS ?

    Enfin, j'ai pu faire fonctionner les fonctions print_recursive et print_recursive_callback. Pour la fonction print_recursive_tab, faut-il décommenter ces deux lignes ? Il me semble qu'il ne se passe rien dans ce cas avec ma variable $tab ? (désolé pour cette question de béotien)
    $result = print_recursive_tab($tab);
    var_dump($result);

    Une 3ème question finalement : dans l'appel de fonction "function print_recursive_callback($tab = array(), $callback, $withKey = true, $niveau = 0)", puis-je changer la valeur de $niveau pour n'afficher que les niveaux supérieurs de profondeur du tableau ?

    Merci en tout les cas pour ce blog.

    Cordialement

    • Bonjour,
      Merci pour vos compliments et remerciements, ça me va droit au coeur.
      En théorie, vous pouvez sélectionner ou tester des couples clés/valeurs via le nom de la clé voire même par sa valeur (il existe les deux types de fonctions en PHP). Concernant le niveau de profondeur, on peut le cibler dans un tableau ou un objet JSON, c'est juste qu'il faudra remonter toute chaîne en connaissant le nom de chaque clé. Cela peut donc être parfois fastidieux.
      Pour ce qui est des flux RSS, que voulez-vous dire exactement ? Parser va lire un flux RSS, pas en créer un. Si vous souhaitez lire (parser) des flux, alors simpleXML est très bien, mais sur de gros volumes, j'aurais tendance à vous conseiller XmlReader qui s'avère être généralement plus efficace (simpleXML peut suffire bien entendu, c'est juste un peu plus lent).

      Je n'ai pas bien saisi vos questions sur les fonctions de récursivité. En théorie, vous copier la fonction (ou les fonctions), vous composer un tableau de données ($tab), et vous l'appelez (en décommentant bien sûr) avec les deux lignes que vous m'avez indiquées. Cela devrait fonctionner. ^^

      La variable $niveau n'est utilisée que par les fonctions en elle-même, pour la récursivité. J'aurais très bien pu utiliser des variables statiques à la place, mais j'ai fait ce choix ici. Donc cela ne vous aidera pas à atteindre un certain niveau de profondeur. En revanche, c'est quelque chose qui pourrait se programmer en effet, de réaliser un retour d'affichage sur un niveau précis. ;-)

  • Déposer un commentaire

    L'adresse de messagerie ne sera pas publiée.* Champs obligatoires