3

我想创建包装类,它将启用密钥重复,而默认哈希不允许它。类应该使用php5中引入的成员重载机制,所以它会模仿标准hash的所有行为。例如,我想要 smth like

$var => obj( :values_arr -> array(
      obj(:key -> 'mykey', :value -> 'val1'), 
      obj(:key -> 'mykey', :value -> 'val2')
    )
)

如果我想获取 $var['mykey'],它应该返回 array('val1', 'val2'),但是如果我想用新的 'mykey' => 'value' 对扩展 obj,我会调用

$val['mykey'][] = 'value'

主要思想是保留了哈希的行为,并且在尝试使用现有密钥分配值之后,它不会被覆盖,而是附加到列表中。

您将如何模仿 php5(5.3 之前)中的其他数据结构?您是否有任何已知的解决方案或示例要分享?

4

2 回答 2

2

像这样

class MultiMap
{
    protected $map = array();

    function __set($key, $val) {
        if(!isset($this->map[$key]))  
           return $this->map[$key] = $val;
        if(!is_array($this->map[$key]))
           $this->map[$key] = array($this->map[$key]);
        $this->map[$key][] = $val;
    }
    function __get($key) {
       return $this->map[$key];
    }
}

$m = new MultiMap;
$m->foo = 1;
$m->foo = 2;
$m->bar = 'zzz';
print_r($m->foo);
print_r($m->bar);

但整个想法对我来说有点奇怪。你能解释一下为什么需要这个吗?

我不清楚为什么需要运算符作为 AST 中的键,也许这样的结构会更方便

   ('op' => 'AND', 'args' => [
        (op => AND, args => [
            (op  => atom, value => word1),
            (op  => atom, value => word2),
        ]),
        (op => AND, args => [
            (op  => atom, value => word3),
            (op  => atom, value => word4),
        ])
    ])
于 2009-11-25T13:50:48.880 回答
0

可以实现数组语法

$val['mykey'] = 'value';

ArrayAccess界面

class MultiHash implements ArrayAccess, IteratorAggregate
{
    protected $data;

    public function offsetGet($offset)
    {
        return $this->data[$offset];
    }
    public function offsetSet($offset, $value)
    {
        if ($offset === null) { // $a[] = ...
            $this->data[] = array($value);
        } else {
            $this->data[$offset][] = $value;
        }
    }
    public function offsetExists($offset)
    {
        return isset($this->data[$offset]);
    }
    public function offsetUnset($offset)
    {
        unset($this->data[$offset]);
    }

    public function getIterator()
    {
        $it = new AppendIterator();
        foreach ($this->data as $key => $values) {
            $it->append(new ConstantKeyArrayIterator($values, 0, $key));
        }
        return $it;
    }
}

class ConstantKeyArrayIterator extends ArrayIterator
{
    protected $key;

    public function __construct($array = array(), $flags = 0, $key = 0)
    {
        parent::__construct($array,$flags);
        $this->key = $key;
    }
    public function key()
    {
        return parent::key() === null ? null : $this->key;
    }
}

我还实现IteratorAggregate了允许对所有单个元素进行迭代。

测试代码

$test = new MultiHash();
$test[] = 'foo';
$test[] = 'bar';
$test['mykey'] = 'val1';
$test['mykey'] = 'val2';
$test['mykey2'] = 'val3';

echo "mykey: ";
var_dump($test['mykey']);

echo "mykey2: ";
var_dump($test['mykey2']);

echo "iterate:\n";
foreach ($test as $key => $value) {
    echo "$key : $value \n";
}

测试输出

mykey: array(2) {
  [0]=>
  string(4) "val1"
  [1]=>
  string(4) "val2"
}
mykey2: array(1) {
  [0]=>
  string(4) "val3"
}
iterate:
0 : foo 
1 : bar 
mykey : val1 
mykey : val2 
mykey2 : val3 
于 2013-02-16T12:16:17.907 回答