我有一个使用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'));
}
答案 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'));