2011-11-14 6 views
0

せずに私はwords.separated.by.dotsキーを使用してデータを格納/アクセスデータを保持するクラスを持っており、それは以下のように振る舞うことを達成するためにしかし、unsetParam()メソッドはひどく実装されていました。私はeval()関数なしでそれを達成する方法を知らなかったので、それが起こった。動作していますが、それは本当に難しいアルゴリズムであり、eval()を使用せずにこれを達成しようとすると楽しいかもしれないことがわかりました。PHPのアルゴリズムがどのように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; 
    } 
} 

試験方法:

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')); 
} 

答えて

1

これはそれですか?

<?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

参照のクリエイティブな使用:) – Kato

+0

非常に良い!どうもありがとうございました! – Marcelo

1

あなただけの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

これははるかに良い答えです、imho;キーはユニークなので、なぜ多次元配列が有用なのでしょうか?私たちがまだ聞いていない説得力のある詳細がない限り、string.with.dotsを使用して保存/取得します。 – Kato

+0

多次元配列は私のニーズに適しています。私のクラスは上のようなものだったし、変わってしまった。 – Marcelo

+0

@Kato、その論理的な結論にあなたの議論をもたらしましょう:このクラス全体がなぜ必要なのでしょうか? :D – Esailija

0

@gustavotkgと@Esailijaは両方のいくつかの素晴らしいアイデアを提供してきました。 unset()を完全に避ける(簡単な場合はquirkyが得られる)、シンプルで分かりやすく、簡単なアプローチです。

<?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')); 

これは、もちろん、$はparamsはときに最も有用であろうが少ない(CPU /メモリDEPTで高価なビットを取得するために開始します)値の1K-10K、たとえば、以下に制限されています