8722 sujets

Développement web côté serveur, CMS

Je vous salut chers Alsanautes. Le titre du post n'est pas très parlant mais bon...
J'ai un petit soucis et j'aurai besoin de votre aide une fois de plus.

Dans toute mon appli j'ai des fichiers de configurations ayant des tableaux
structurés de la manière suivante


$conf = [
	'db' => [
		'host' => 'localhost',
		'username' => 'root',
		'password' => 'root',
		'database' => 'test',
		'options', => [
			'case' => 'inherit'
		]
	],

	'layout' => [
		'styles' => [
			'vendor' => [
				'bootstrap' => ['bootstrap', 'bootstrap-theme'], 
				'fontawesome'
			]
		],
		'scripts' => ['jquery', 'datatables']
	]
];


J'ai donc envie de créer une fonction à travers laquelle on pourra récupérer une valeur du tableau simplement.
En faisant par exemple

$host = get('db.host'); // retourne localhost
$case = get('db.options.case'); // retourne inherit
$vendor = get('layout.styles.vendor.bootstrap'); // retourne ['bootstrap', 'bootstrap-theme']


Le but est de parcourrir l'arborescence à chaque point(.) jusqu'à atteindre l'élément souhaité.

J'ai fait un petit script qui fonctionne mais qui n'est pas évolutif (puisque si le tableau va au délàs de 5 niveaux, la fonction s'arrête)

public static function get(?string $conf = null)
{
	if (null === $conf)
	{
		return self::$_config;
	}
	$conf = explode('.', $conf);
	$count = count($conf);

	
	if ($count == 1) 
	{
		return self::$_config[$conf[0]] ?? null;
	}
	if ($count == 2) 
	{
		return self::$_config[$conf[0]][$conf[1]] ?? null;
	}
	if ($count == 3) 
	{
		return self::$_config[$conf[0]][$conf[1]][$conf[2]] ?? null;
	}
	if ($count == 4) 
	{
		return self::$_config[$conf[0]][$conf[1]][$conf[2]][$conf[3]] ?? null;
	}
	if ($count == 5) 
	{
		return self::$_config[$conf[0]][$conf[1]][$conf[2]][$conf[3]][$conf[4]] ?? null;
	}
	return null;
}


Je souhaiterai donc faire un script capable de parcourrir tout le tableau quelque soit sa profondeur. Si vous avez une solution pour moi j'en serai ravi Smiley smile
Modifié par Dimtrovich (26 Jul 2020 - 16:19)
Modérateur
Bonjour,

L'idée est d'utiliser une fonction récursive (qui s'appelle elle-même).

Par exemple :
function magicGet($_config, $conf = null)
{
	if ($_config === null) return null;
	if ($conf === null) return $_config;
	$conf = explode('.', $conf);
	$count = count($conf);
	if ($count == 1) return $_config[$conf[0]] ?? null;
	$conf2 = $conf[1];
	for ($k = 2; $k < $count; $k++) $conf2.=".".$conf[$k];
	return magicGet($_config[$conf[0]] ?? null, $conf2);
}

$host = magicGet($_config,'db.host');
// retourne localhost
print_r($host);
echo "<br>";
$case = magicGet($_config,'db.options.case');
// retourne inherit
print_r($case);
echo "<br>";
$vendor = magicGet($_config,'layout.styles.vendor.bootstrap');
// retourne ['bootstrap', 'bootstrap-theme']
print_r($vendor);
echo "<br>";

Amicalement,
Meilleure solution
Merci beaucoup @parsimonhi.
ça marche et j'ai pu adapter à mon application..

Maintenant je encore un petit soucis. si je veux faire un setter correspondant comment est-ce que je procède.
Voici ce que j'avais fait


public static function set(string $config, $value)
    {
        $config = explode('.', $config);
        $count = count($config);

        if ($count == 1) 
        {
            self::$_config[$config[0]] = $value;
        }
        if ($count == 2) 
        {
            self::$_config[$config[0]][$config[1]] = $value;
        }
        if ($count == 3) 
        {
            self::$_config[$config[0]][$config[1]][$config[2]] = $value;
        }
        if ($count == 4) 
        {
            self::$_config[$config[0]][$config[1]][$config[2]][$config[3]] = $value;
        }
        if ($count == 5) 
        {
            self::$_config[$config[0]][$config[1]][$config[2]][$config[3]][$config[4]] = $value;
        }
    }


Merci d'avance Smiley murf
Modérateur
Bonjour,

On peut aussi écrire une fonction récursive pour faire le set. L'idée supplémentaire est que l'on donne en 1er paramètre de la fonction une référence vers un sous-tableau du tableau initial (d'où l'ajout d'un "&" devant le nom de cette référence).

Par exemple (comme pour la fonction magicSet(), je n'ai pas cherché à traiter tous les cas d'erreurs possibles qui dépendent du contexte : à adapter donc) :
function magicSet(&$_subConfig, $conf = null, $value = null)
{
	// à noter le "&" devant $_subConfig,
	// qui indique qu'on passe le paramètre par référence
	if ($_subConfig === null) return;
	if ($conf === null) return;
	$conf = explode('.', $conf);
	$count = count($conf);
	if ($count == 1)
	{
		// on a fini, on affecte $value à l'élément approprié de $_subConfig
		// $_subConfig étant un sous-tableau de $_config, ou $_config lui-même
		$_subConfig[$conf[0]] = $value;
		return;
	}
	// $count est au moins égal à 2 quand on passe ici
	$conf2 = $conf[1];
	for ($k = 2; $k < $count; $k++) $conf2.=".".$conf[$k];
	if (!isset($_subConfig[$conf[0]]))
	{
		// $_subConfig[$conf[0]] n'existe pas
		// on lui affecte un tableau vide qui aura plus tard au moins un élément
		$_subConfig[$conf[0]] = array();
	}
	magicSet($_subConfig[$conf[0]], $conf2, $value);
}
magicSet($_config,'db.host','otherHost');
print_r($_config);
echo "<br>";

Amicalement,