Php算法 - 如何在没有eval的情况下实现

时间:2011-11-14 17:05:05

标签: php arrays algorithm

我有一个使用words.separated.by.dots键保存数据存储/访问数据的类,它的行为如下:

    $object = new MyArray()
    $object->setParam('user.name','marcelo');
    $object->setParam('user.email','some@email.com');

    $object->getParams();

    /*
    array(
        'user' => array(
            'name' => 'marcelo',
            'email' => 'some@email.com'
        )
    );
    */

它正在工作,但是方法unsetParam()实现得非常糟糕。发生这种情况是因为我不知道如何在没有eval()函数的情况下实现这一点。虽然它有效,但我发现这是一个非常具有挑战性的算法,如果没有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'));
}

3 个答案:

答案 0 :(得分: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
)
*/

答案 1 :(得分: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;
    }
}

答案 2 :(得分:0)

@gustavotkg和@Esailija都提出了一些很棒的想法。这是另一个简单,易于理解和简短的方法,它完全避免了unset()(在某些情况下可以获得quirky)。

当$ params被限制为小于1k-1k的值(在CPU /内存部门开始变得有点贵)时,这当然是最有用的:

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