2010-11-11 5 views
1

Je suis en train de créer un petit système de modèles et je cherche un moyen d'invoquer des tableaux associatifs multidimensionnels en utilisant des points. Par exemple:Appel de tableaux associatifs multidimensionnels dans des modèles

$animals = array(
      'four-legged' => array (
          'cute' => 'no', 
          'ugly' => 'no', 
          'smart' => array('best' => 'dog','worst' => 'willy') 
         ), 
      '123' => '456', 
      'abc' => 'def' 
); 

Puis, dans mon modèle, si je voulais montrer 'chien', je mettrais:

{} a.four-legged.smart.best

+0

Qu'avez-vous essayé ? Avez-vous essayé d'écrire une expression pour remplacer les points avec des crochets et des guillemets? – GWW

+0

En théorie, oui. Mais alors mon résultat serait une chaîne, pas un nom de variable valide. Ce serait "$ a ['à quatre pattes'] ['intelligent'] ['meilleur']". – MichaelBrett

+0

@GWW vous ne voulez vraiment pas faire eval si vous pouvez l'aider. –

Répondre

5

Eh bien, d'une chaîne avec four-legged.smart.worst:

function getElementFromPath(array $array, $path) { 
    $parts = explode('.', $path); 
    $tmp = $array; 
    foreach ($parts as $part) { 
     if (!isset($tmp[$part])) { 
      return ''; //Path is invalid 
     } else { 
      $tmp = $tmp[$part]; 
     } 
    } 
    return $tmp; //If we reached this far, $tmp has the result of the path 
} 

Alors vous pouvez appeler:

$foo = getElementFromPath($array, 'four-legged.smart.worst'); 
echo $foo; // willy 

Et si vous voulez écrire des éléments, ce n'est pas beaucoup plus difficile (vous avez juste besoin d'utiliser des références, et quelques contrôles à défaut, les valeurs si le chemin n'existe pas) ...:

function setElementFromPath(array &$array, $path, $value) { 
    $parts = explode('.', $path); 
    $tmp =& $array; 
    foreach ($parts as $part) { 
     if (!isset($tmp[$part]) || !is_array($tmp[$part])) { 
      $tmp[$part] = array(); 
     } 
     $tmp =& $tmp[$part]; 
    } 
    $tmp = $value; 
} 

Edit: Comme cela est dans un système de modèle, il peut être utile de « compilation » le tableau en bas à une seule dimension une fois, plutôt que de traverser chaque fois (pour des raisons de performance) ...

function compileWithDots(array $array) { 
    $newArray = array(); 
    foreach ($array as $key => $value) { 
     if (is_array($value)) { 
      $tmpArray = compileWithDots($value); 
      foreach ($tmpArray as $tmpKey => $tmpValue) { 
       $newArray[$key . '.' . $tmpKey] = $tmpValue; 
      } 
     } else { 
      $newArray[$key] = $value; 
     } 
    } 
    return $newArray; 
} 

Donc, cela convertirait:

$animals = array(
'four-legged' => array (
    'cute' => 'no', 
    'ugly' => 'no', 
    'smart' => array(
    'best' => 'dog', 
    'worst' => 'willy' 
) 
), 
'123' => '456', 
'abc' => 'def' 
); 

Dans

array(
    'four-legged.cute' => 'no', 
    'four-legged.ugly' => 'no', 
    'four-legged.smart.best' => 'dog', 
    'four-legged.smart.worst' => 'willy', 
    '123' => '456', 
    'abc' => 'def', 
); 

Ensuite, votre recherche devient juste $value = isset($compiledArray[$path]) ? $compiledArray[$path] : ''; au lieu de $value = getElementFromPath($array, $path);

Il négocie pré-informatique pour la vitesse en ligne (vitesse dans la boucle) ...

+0

Par curiosité, pourquoi faites-vous un contrôle is_array là? – MichaelBrett

+0

Où? Il y a deux contrôles 'is_array' dans le code ci-dessus ... De quoi parlez-vous (celui de' setElementFromPath' ou celui de 'compileWithDots')? – ircmaxell

+0

J'ai remarqué, aussi, que le réglage d'un élément efface tous les autres éléments. – MichaelBrett

Questions connexes