2011-11-14 2 views
0

J'ai une classe qui conserve les données des banques de données/accès à l'aide des touches de words.separated.by.dots et il se comporte comme ce qui suit:algorithme Php - Comment y parvenir sans eval

$object = new MyArray() 
    $object->setParam('user.name','marcelo'); 
    $object->setParam('user.email','[email protected]'); 

    $object->getParams(); 

    /* 
    array(
     'user' => array(
      'name' => 'marcelo', 
      'email' => '[email protected]' 
     ) 
    ); 
    */ 

Il travaille , mais la méthode unsetParam() a été horriblement implémentée. Cela est arrivé parce que je ne savais pas comment y parvenir sans la fonction eval(). Bien que cela fonctionne, j'ai trouvé que c'était un algorithme très difficile et que vous pourriez trouver amusant d'essayer d'y parvenir sans eval().

class MyArray { 
    /** 
    * @param string $key 
    * @return Mura_Session_Abstract 
    */ 
    public function unsetParam($key) 
    { 
     $params = $this->getParams(); 
     $tmp = $params; 
     $keys = explode('.', $key); 

     foreach ($keys as $key) { 
      if (!isset($tmp[$key])) { 
       return $this; 
      } 
      $tmp = $tmp[$key]; 
     } 

     // bad code! 
     $eval = "unset(\$params['" . implode("']['", $keys) . "']);"; 
     eval($eval); 

     $this->setParams($params); 
     return $this; 
    } 
} 

La méthode d'essai:

public function testCanUnsetNestedParam() 
{ 
    $params = array(
     '1' => array(
      '1' => array(
       '1' => array(
        '1' => 'one', 
        '2' => 'two', 
        '3' => 'three', 
       ), 
       '2' => array(
        '1' => 'one', 
        '2' => 'two', 
        '3' => 'three', 
       ), 
      ) 
     ), 
     '2' => 'something' 
    ); 

    $session = $this->newSession(); 
    $session->setParams($params); 

    unset($params['1']['1']['1']); 
    $session->unsetParam('1.1.1'); 

    $this->assertEquals($params, $session->getParams()); 
    $this->assertEquals($params['1']['1']['2'], $session->getParam('1.1.2')); 
} 

Répondre

1

Est-ce cela?

<?php 
$params = array(
    '1' => array(
     '1' => array(
     '1' => array(
      '1' => 'one', 
      '2' => 'two', 
      '3' => 'three', 
     ), 
     '2' => array(
      '1' => 'one', 
      '2' => 'two', 
      '3' => 'three', 
     ), 
     ) 
    ), 
    '2' => 'something' 
    ); 

function unsetParam(&$array, $paramString) { 
$cur =& $array; 
$splitted = explode(".", $paramString); 
$len = count($splitted) - 1; 

    for($i = 0; $i < $len; ++$i) { 

     if(isset($cur[ $splitted[ $i ] ])) { 
     $cur =& $cur[ $splitted[ $i ] ]; 
     } 
     else { 
     return false; 
     } 


    } 

unset($cur[ $splitted[$i] ]); 


} 

unsetParam($params, "1.1.1"); 

print_r($params); 

/* 
Array 
(
    [1] => Array 
    (
     [1] => Array 
     (
      [2] => Array 
      (
       [1] => one 
       [2] => two 
       [3] => three 
      ) 

     ) 

    ) 

    [2] => something 
) 
*/ 
+0

utilisation créative des références :) – Kato

+0

Très agréable! Merci beaucoup! – Marcelo

1

Vous pouvez rendre votre code plus facile si vous ne divisez à un tableau de multidimension dans votre méthode getParams:

class MyArray { 
    private $params = array(); 

    public function setParam($key, $value) { 
     $this->params[$key] = $value; 
    } 
    /** 
    * @param string $key 
    * @return Mura_Session_Abstract 
    */ 
    public function unsetParam($key) 
    { 
     unset($this->params[$key]); 
     return $this; 
    } 

    public function getParams() { 
     $retval = array(); 
     foreach ($this->params as $key => $value) { 
      $aux = &$retval; 
      foreach (explode(".", $key) as $subkey) { 
       if (!isset($aux[$subkey])) $aux[$subkey] = array(); 
       $aux = &$aux[$subkey]; 
      } 
      $aux = $value; 
     } 
     return $retval; 
    } 
} 
+0

C'est de loin la meilleure réponse, à mon humble avis; les clés sont uniques alors pourquoi un tableau multidimensionnel est-il utile? Juste stocker/récupérer en utilisant le string.with.dots à moins qu'il y ait des détails convaincants que nous n'avons pas encore entendu? – Kato

+0

La matrice multidimensionnelle s'adapte mieux à mes besoins. Ma classe ressemblait beaucoup à celle ci-dessus et j'ai fini par changer. – Marcelo

+0

@Kato, amenons votre argument à sa conclusion logique: pourquoi toute cette classe est-elle même nécessaire? : D – Esailija

0

@gustavotkg et @Esailija ont tous deux offert quelques bonnes idées. Voici une autre approche simple, facile à comprendre, et courte qui évite unset() tout à fait (qui peut obtenir quirky dans certains cas).

Ceci, bien sûr, être le plus utile quand $ params est limitée à moins que, par exemple, 1k-10k des valeurs (qui commence à être un peu cher dans le département de CPU/mémoire):

<?php 

$params = array(
    '1' => array(
     '1' => array(
     '1' => array(
      '1' => 'one-one', 
      '2' => 'one-two', 
      '3' => 'one-three', 
     ), 
     '2' => array(
      '1' => 'two-one', 
      '2' => 'two-two', 
      '3' => 'two-three', 
     ), 
    ) 
    ), 
    '2' => 'something' 
); 

function filterParams($params, $refKey, $base = '') { 
    $newvals = array(); 
    foreach($params as $k=>$v) { 
     $joinedKey = $base? $base . '.' . $k : $k; 
     if($joinedKey != $refKey) { 
     $newvals[$k] = is_array($v)? filterParams($v, $refKey, $joinedKey) : $v; 
     } 
    } 
    return $newvals; 
} 

var_dump(filterParams($params, '1.1.2')); 
Questions connexes