预定义接口
在线手册:中文 英文
PHP手册

ArrayAccess(数组式访问)接口

(No version information available, might only be in SVN)

简介

提供像访问数组一样访问对象的能力的接口。

接口摘要

ArrayAccess {
/* 方法 */
abstract public boolean offsetExists ( mixed $offset )
abstract public mixed offsetGet ( mixed $offset )
abstract public void offsetSet ( mixed $offset , mixed $value )
abstract public void offsetUnset ( mixed $offset )
}

Example #1 Basic usage

<?php
class obj implements arrayaccess {
    private 
$container = array();
    public function 
__construct() {
        
$this->container = array(
            
"one"   => 1,
            
"two"   => 2,
            
"three" => 3,
        );
    }
    public function 
offsetSet($offset$value) {
        if (
is_null($offset)) {
            
$this->container[] = $value;
        } else {
            
$this->container[$offset] = $value;
        }
    }
    public function 
offsetExists($offset) {
        return isset(
$this->container[$offset]);
    }
    public function 
offsetUnset($offset) {
        unset(
$this->container[$offset]);
    }
    public function 
offsetGet($offset) {
        return isset(
$this->container[$offset]) ? $this->container[$offset] : null;
    }
}

$obj = new obj;

var_dump(isset($obj["two"]));
var_dump($obj["two"]);
unset(
$obj["two"]);
var_dump(isset($obj["two"]));
$obj["two"] = "A value";
var_dump($obj["two"]);
$obj[] = 'Append 1';
$obj[] = 'Append 2';
$obj[] = 'Append 3';
print_r($obj);
?>

以上例程的输出类似于:

bool(true)
int(2)
bool(false)
string(7) "A value"
obj Object
(
    [container:obj:private] => Array
        (
            [one] => 1
            [three] => 3
            [two] => A value
            [0] => Append 1
            [1] => Append 2
            [2] => Append 3
        )

)

Table of Contents


预定义接口
在线手册:中文 英文
PHP手册
PHP手册 - N: ArrayAccess(数组式访问)接口

用户评论:

Per (20-May-2011 10:16)

It bit me today, so putting it here in the hope it will help others:
If you call array_key_exists() on an object of a class that implements ArrayAccess, ArrayAccess::offsetExists() wil NOT be called.

uramihsayibok, gmail, com (05-Aug-2010 11:34)

EDITOR NOTE: You can return by reference in offsetGet as of PHP 5.3.4.

If you find yourself facing the dreaded "Indirect modification of overloaded element of $class has no effect" then don't worry too much: there's a clever solution. While you *CANNOT* return by-reference with offsetGet, you can return objects which _also_ implement ArrayAccess...

Example:
<?php

// sanity and error checking omitted for brevity
// note: it's a good idea to implement arrayaccess + countable + an
// iterator interface (like iteratoraggregate) as a triplet

class RecursiveArrayAccess implements ArrayAccess {

    private
$data = array();

   
// necessary for deep copies
   
public function __clone() {
        foreach (
$this->data as $key => $value) if ($value instanceof self) $this[$key] = clone $value;
    }

    public function
__construct(array $data = array()) {
        foreach (
$data as $key => $value) $this[$key] = $value;
    }

    public function
offsetSet($offset, $data) {
        if (
is_array($data)) $data = new self($data);
        if (
$offset === null) { // don't forget this!
           
$this->data[] = $data;
        } else {
           
$this->data[$offset] = $data;
        }
    }

    public function
toArray() {
       
$data = $this->data;
        foreach (
$data as $key => $value) if ($value instanceof self) $data[$key] = $value->toArray();
        return
$data;
    }

   
// as normal
   
public function offsetGet($offset) { return $this->data[$offset]; }
    public function
offsetExists($offset) { return isset($this->data[$offset]); }
    public function
offsetUnset($offset) { unset($this->data); }

}

$a = new RecursiveArrayAccess();
$a[0] = array(1=>"foo", 2=>array(3=>"bar", 4=>array(5=>"bz")));
// oops. typo
$a[0][2][4][5] = "baz";

//var_dump($a);
//var_dump($a->toArray());

// isset and unset work too
//var_dump(isset($a[0][2][4][5])); // equivalent to $a[0][2][4]->offsetExists(5)
//unset($a[0][2][4][5]); // equivalent to $a[0][2][4]->offsetUnset(5);

// if __clone wasn't implemented then cloning would produce a shallow copy, and
$b = clone $a;
$b[0][2][4][5] = "xyzzy";
// would affect $a's data too
//echo $a[0][2][4][5]; // still "baz"

?>

max at flashdroid dot com (06-Apr-2010 02:49)

Objects implementing ArrayAccess may return objects by references in PHP 5.3.0.

You can implement your ArrayAccess object like this:

    class Reflectable implements ArrayAccess {

        public function set($name, $value) {
            $this->{$name} = $value;
        }

        public function &get($name) {
            return $this->{$name};
        }

        public function offsetGet($offset) {
            return $this->get($offset);
        }

        public function offsetSet($offset, $value) {
            $this->set($offset, $value);
        }

        ...

    }

This base class allows you to get / set your object properties using the [] operator just like in Javascript:

    class Boo extends Reflectable {
        public $name;
    }

    $obj = new Boo();
    $obj['name'] = "boo";
    echo $obj['name']; // prints boo

Cintix (29-Oct-2009 09:32)

To take full advantages of all array features with ArrayAccess, then you would need to implements Countable and Iterator

Like this.

<?php

class ArrayOfColorModel implements ArrayAccess, Iterator, Countable {
    private
$container = array();

    public function
__construct() {
    }

    public function
offsetSet($offset,$value) {
         if (
$value instanceof ColorModel){
            if (
$offset == "") {
               
$this->container[] = $value;
            }else {
               
$this->container[$offset] = $value;
            }
        } else {
            throw new
Exception("Value have to be a instance of the Model ColorModel");
        }
    }

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

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

    public function
offsetGet($offset) {
        return isset(
$this->container[$offset]) ? $this->container[$offset] : null;
    }

    public function
rewind() {
       
reset($this->container);
    }

    public function
current() {
        return
current($this->container);
    }

    public function
key() {
        return
key($this->container);
    }

    public function
next() {
        return
next($this->container);
    }

    public function
valid() {
        return
$this->current() !== false;
    }   

    public function
count() {
     return
count($this->container);
    }

}

?>

Now you can using it like any other array.

<?php
   
   $array
= new ArrayOfColorModel();
   foreach (
$array as $model) {
       
var_export($model);
   }

  
// OR

  
for($i=0;$i<count($array);$i++){
       
var_export($array[$i]);
   }

?>

AryehGregor+php-comment at gmail dot com (09-Jan-2009 01:33)

Note that at least in PHP 5.1, objects implementing ArrayAccess cannot return objects by reference.  See http://bugs.php.net/bug.php?id=34783 .  If you have code like

<?php
$x
= &$y[0];
?>

then this will (as far as I can tell) *always* fail unless $y is a real array -- it cannot work if $y is an object implementing ArrayAccess.  If your offsetGet() function returns by reference, you get the fatal error "Declaration of MyClass::offsetGet() must be compatible with that of ArrayAccess::offsetGet()".  If you try to have it return by value, however, you get the (contradictory) fatal error "Objects used as arrays in post/pre increment/decrement must return values by reference", at least in my version of PHP.

It is therefore not possible to take arbitrary code dealing with arrays and try to substitute an object of your own for an array, even if all of the normal array functions didn't fail as well (which they do, or at least some of them).