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

发布于 2024-12-15 14:21:56 字数 2233 浏览 1 评论 0原文

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

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

    $object->getParams();

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

它正在工作,但方法 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'));
}

I have a class that keeps data stores/access data by using words.separated.by.dots keys and it behaves like the following:

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

    $object->getParams();

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

It is working, but the method unsetParam() was horribly implemented. That happened because i didn't know how to achieve that without eval() function. Although it is working, I found that it was a really challenging algorithm and that you might find fun trying to achieve that without 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;
    }
}

The test method:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

七堇年 2024-12-22 14:21:56

是这个吗?

<?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
)
*/

Is this it?

<?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
)
*/
月下凄凉 2024-12-22 14:21:56

如果您仅在 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;
    }
}

You could make your code easier if you only split to a multidimension array in your getParams method:

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;
    }
}
潜移默化 2024-12-22 14:21:56

@gustavotkg 和@Esailija 都提供了一些很棒的想法。这是另一种简单、易于理解且简短的方法,可以完全避免 unset() (可以得到 在某些情况下很奇怪)。

当然,当 $params 限制为小于 1k-10k 值时(这在 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'));

@gustavotkg and @Esailija have both offered some great ideas. Here is another simple, easy to understand, and short approach that avoids unset() altogether (which can get quirky in some cases).

This would, of course, be most useful when $params is limited to less than, say, 1k-10k of values (which starts to get a bit pricey in the CPU/memory dept):

<?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'));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文