views:

160

answers:

4

Hello,

I have an associative array that I might need to access numerically (ie get the 5th key's value).

$data = array(
    'one' => 'something', 
    'two' => 'else', 
    'three' => 'completely'
) ;

I need to be able to do:

$data['one']

and

$data[0]

to get the same value, 'something'.

My initial thought is to create a class wrapper that implements ArrayAccess with offsetGet() having code to see if the key is numeric and act accordingly, using array_values:

class MixedArray implements ArrayAccess {

    protected $_array = array();

    public function __construct($data) {
        $this->_array = $data;
    }

    public function offsetExists($offset) {
        return isset($this->_array[$offset]);
    }

    public function offsetGet($offset) {
        if (is_numeric($offset) || !isset($this->_array[$offset])) {
            $values = array_values($this->_array) ;
            if (!isset($values[$offset])) {
                return false ;
            }
            return $values[$offset] ;
        }                
        return $this->_array[$offset];
    }

    public function offsetSet($offset, $value) {
        return $this->_array[$offset] = $value;
    }

    public function offsetUnset($offset) {
        unset($this->_array[$offset]);
    }    

}

I am wondering if there isn't any built in way in PHP to do this. I'd much rather use native functions, but so far I haven't seen anything that does this.

Any ideas?

Thanks,
Fanis

+4  A: 
how about this 

$data = array(
    'one' => 'something', 
    'two' => 'else', 
    'three' => 'completely'
) ;

then 
$keys = array_keys($data);

Then 
$key = $keys[$index_you_want];

Then 
echo $data[$key];
Wbdvlpr
Right, but I don't know in advance if I'll be doing numeric or associative. I need both to work for whoever else ends up using my array wrapper.
Fanis
it should work for both.
Wbdvlpr
+1  A: 

There isn't a built-in way to do this.

If it's a one-off thing you could use something like:

$array = array_merge($array, array_values($array));

This won't update as you add new items to the array though.

Greg
This is pretty much readonly (database result set), so I reckon that could work. It would, however, eat up more memory which might be unwanted in large sets. I'll keep it in mind in the end since it may just well be the fastest way for smaller sets, rather than have 2 layers of wrappers over it
Fanis
A: 

i noticed you mentioned it is a readonly database result set

if you are using mysql then you could do something like this

$result = mysql_query($sql);
$data = mysql_fetch_array($result);

mysql_fetch_array returns an array with both associative and numeric keys

http://nz.php.net/manual/en/function.mysql-fetch-array.php

bumperbox
Ah, very good catch. I had forgotten about that. I am using PEAR::DB however, which doesn't seem to have a publically exposed such option. I guess I could just dive into PEAR/DB/mysql.php::fetchInto() and change it to use MYSQL_BOTH, but I'd rather not hack it like that :)Still, you gave me something to think about, thanks
Fanis
A: 

Sometimes it's easier to check if you have an associative key or an index with is_int()

if(is_int($key))
    return current(array_slice($data, $key, 1));
else
    return $data[$key];
rojoca
I like your array_slice option, thanks. However I need this to be transparent to whoever uses my code. They might access the array numerically or via a string key.I am experimenting with an ArrayAccess wrapper. So far it looks good though there are a few tweaks to make, such as how to pass this to native functions that expect arrays (ie array_rand()), but I'm getting there.
Fanis