Making a PHP object behave like an array?

2019-01-31 09:01发布

问题:

I'd like to be able to write a PHP class that behaves like an array and uses normal array syntax for getting & setting.

For example (where Foo is a PHP class of my making):

$foo = new Foo();

$foo['fooKey'] = 'foo value';

echo $foo['fooKey'];

I know that PHP has the _get and _set magic methods but those don't let you use array notation to access items. Python handles it by overloading __getitem__ and __setitem__.

Is there a way to do this in PHP? If it makes a difference, I'm running PHP 5.2.

回答1:

If you extend ArrayObject or implement ArrayAccess then you can do what you want.

  • ArrayObject
  • ArrayAccess


回答2:

Nope, casting just results in a normal PHP array -- losing whatever functionality your ArrayObject-derived class had. Check this out:

class CaseInsensitiveArray extends ArrayObject {
    public function __construct($input = array(), $flags = 0, $iterator_class =     'ArrayIterator') {
        if (isset($input) && is_array($input)) {
            $tmpargs = func_get_args();
            $tmpargs[0] = array_change_key_case($tmpargs[0], CASE_LOWER);
            return call_user_func_array(array('parent', __FUNCTION__), $tmp    args);
        }
        return call_user_func_array(array('parent', __FUNCTION__), func_get_args());
    }

    public function offsetExists($index) {
        if (is_string($index)) return parent::offsetExists(strtolower($index));
        return parent::offsetExists($index);
    }

    public function offsetGet($index) {
        if (is_string($index)) return parent::offsetGet(strtolower($index));
        return parent::offsetGet($index);
    }

    public function offsetSet($index, $value) {
        if (is_string($index)) return parent::offsetSet(strtolower($index, $value));
        return parent::offsetSet($index, $value);
    }

    public function offsetUnset($index) {
        if (is_string($index)) return parent::offsetUnset(strtolower($index));
        return parent::offsetUnset($index);
    }
}

$blah = new CaseInsensitiveArray(array(
    'A'=>'hello',
    'bcD'=>'goodbye',
    'efg'=>'Aloha',
));

echo "is array: ".is_array($blah)."\n";

print_r($blah);
print_r(array_keys($blah));

echo $blah['a']."\n";
echo $blah['BCD']."\n";
echo $blah['eFg']."\n";
echo $blah['A']."\n";

As expected, the array_keys() call fails. In addition, is_array($blah) returns false. But if you change the constructor line to:

$blah = (array)new CaseInsensitiveArray(array(

then you just get a normal PHP array (is_array($blah) returns true, and array_keys($blah) works), but all of the functionality of the ArrayObject-derived subclass is lost (in this case, case-insensitive keys no longer work). Try running the above code both ways, and you'll see what I mean.

PHP should either provide a native array in which the keys are case-insensitive, or make ArrayObject be castable to array without losing whatever functionality the subclass implements, or just make all array functions accept ArrayObject instances.



标签: php arrays oop