使用数字字符串键对数组进行处理

时间:2012-10-11 19:19:11

标签: php arrays

要理解我为什么要这样做,请阅读this及其下的评论。请考虑以下代码:

$obj = new stdClass;
$obj->{10} = 'Thing';

$objArray = (array) $obj;
var_dump($objArray);

产地:

array(1) {
  ["10"]=>
  string(5) "Thing"
}

现在,我无法通过$objArray['10']访问它,因为PHP会将数字字符串键转换为整数键。在将数组转换为对象时,手册明确指出“整数属性是不可访问的”。或者是他们?

为证明文档错误,我创建了一个类:

class strKey implements ArrayAccess
{
    private $arr;
    public function __construct(&$array)
    {
        $this->arr = &$array;
    }

    public function offsetExists($offset)
    {
        foreach ($this->arr as $key => $value)
        {
            if ($key == $offset)
            {
                return true;
            }
        }
        return false;
    }

    public function offsetGet($offset)
    {
        foreach ($this->arr as $key => $value)
        {
            if ($key == $offset)
            {
                return $value;
            }
        }
        return null;
    }

    public function offsetSet($offset, $value)
    {
        foreach($this->arr as $key => &$thevalue)
        {
            if ($key == $offset)
            {
                $thevalue = $value;
                return;
            }
        }

        // if $offset is *not* present...
        if ($offset === null)
        {
            $this->arr[] = $value;
        }
        else
        {
            // this won't work with string keys
            $this->arr[$offset] = $value;
        }
    }

    // can't implement this
    public function offsetUnset($offset)
    {
        foreach ($this->arr as $key => &$value)
        {
            if ($key == $offset)
            {
                //$value = null;
            }
        }
    }
}

现在,我可以(demo)

$b = new strKey($objArray);

echo $b['10']; // Thing
$b['10'] = 'Something else';

// because the classes works with a reference to the original array,
// this will give us a modified array:
var_dump($objArray); 

最后一个难题是,如何取消设置其键为数字字符串的元素?我尝试使用ArrayIteratorkey()next()等,但它不起作用。我无法找到解决这些问题的方法。

任何解决方案都应该与原始数组一起使用,而不是创建副本并替换原始数据。

2 个答案:

答案 0 :(得分:3)

你可以尝试用array_splice()删除它,如果你知道它的偏移量(foreach (...) { $offset++; ... }),但是将数据存储在这样的数组中,确实不是一个好主意。您应该使用foreach将这些对象转换为数组:

foreach ( $obj as $key => $value )
    $array[$key] = $value;

答案 1 :(得分:0)

根据pozs的建议,这是结果offsetUnset()。我还添加了一个新的offsetSet(),它支持添加数字键。

public function offsetUnset($offset)
{
    $off = 0;

    foreach ($this->arr as $key => $value)
    {
        if ($key === $offset)
        {
            array_splice($this->arr, $off, 1);
            return;
        }
        $off++;
    }       
}

public function offsetSet($offset, $value)
{
    foreach($this->arr as $key => &$thevalue)
    {
        if ($key === $offset)
        {
            $thevalue = $value;
            return;
        }
    }

    // if $offset is *not* present...
    if ($offset === null)
    {
        $this->arr[] = $value;
    }
    // it's a numeric string key, now we have to hack it
    else if (strval(intval($offset)) === $offset)
    {
        // create new array via loophole:
        $tempObj = new stdClass;
        $tempObj->{$offset} = $value;

        // append to old array (+= doesn't create copies)
        $this->arr += (array) $tempObj;
        unset($tempObj);
    }
    // we are dealing with a normal key
    else
    {
        $this->arr[$offset] = $value;
    }
}

我正式击败了PHP。耶!