Eae! Hoje vou falar sobre uma das interfaces do PHP!

Bom, o assunto de hoje é a ArrayAccess, que apesar de simples, possibilita que uma classe seja manipulada como um array.

A ArrayAccess, obriga que a classe implemente 4 métodos, são eles:

public boolean offsetExists(mixed $offset)
public mixed offsetGet (mixed $offset)
public void offsetSet(mixed $offset, mixed $value)
public void offsetUnset(mixed $offset)

Através desses métodos, você conseguirá acessar a sua classe como se fosse um array, com algumas restrições é claro :)

Para demonstrar o uso da ArrayAccess, usarei as mesmas classes usadas do post anteriror, só adicionei a classe CarrinhoCompras onde será posteriormente implementada a ArrayAccess.

class Produto
{
	private $nome;
	private $preco;

	public function __construct($nome, $preco)
	{
		$this->nome = $nome;
		$this->preco = $preco;
	}

	/** GETTERS AND SETTERS **/
}

class Item implements Countable
{
	private $produto;
	private $quantidade;

	public function __construct(Produto $produto, $quantidade)
	{
		$this->produto = $produto;
		$this->quantidade = $quantidade;
	}

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

class CarrinhoCompras
{
	private $itens;
	private $data;

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

Nesse exemplo, continuamos com nosso contexto de e-commerce, a classe Item possui um Produto e a quantidade desejada desse produto, e a classe CarrinhoCompras possui todos os Itens que estão sendo vendidos. Bem simples, apenas para demonstração :)

Agora sim, vamos ao que interessa! O atributo $itens, é um array de Itens, para acessar ele poderíamos criar um método getItens(), ou qualquer outro método que acesse esse atributo, mas aqui vou demonstrar como acessar ele através da ArrayAccess.

A classe CarrinhoCompras deve implementar a interface ArrayAccess, e implementar todos os métodos acima citados, como no exemplo abaixo.

class CarrinhoCompras implements ArrayAccess
{
	private $itens;
	private $data;

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

	public function offsetSet($offset, $value)
	{
		var_dump(__METHOD__);
        $this->itens[$offset] = $value;
    }

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

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

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

No exemplo eu coloquei var_dump(__METHOD__) dentro de cada método para que você possa ver quando cada método é chamado. Agora vamos executar alguns testes para que você possa ver a utilização da ArrayAccess.

$produto = new Produto('Livro PHP', 78.50);
$item = new Item($produto, 5);

$produto1 = new Produto('Livro Java', 88.50);
$item1 = new Item($produto1, 1);

$carrinho = new CarrinhoCompras(new DateTime());
$carrinho[0] = $item;
$carrinho[1] = $item1;

var_dump($carrinho[0]);

Fácil não? Agora a sua classe é acessível como um array! Mas agora vamos as restrições :)

// Isso não funciona!
// Apesar de a classe ser acessível como um array, ela não é um array...
// Fazendo isso, você terá como resultado um foreach de todos os atributos public
foreach ($carrinho as $c)
var_dump($c);

// Isso também não!
array_push($carrinho, 'teste');

// Isso funciona!
// Mas não como de costume...
// O indice vazio, no caso de um array, teria o mesmo comportamento
// Que array_push(), mas no caso de um objeto
// O indice é covertido para NULL
$carrinho[] = 'teste';

Você pode continuar chamando os métodos normalmente, ou seja.

// Isso funciona!
$carrinho->offsetExists(0);

Abaixo uma breve explicação de cada método.

// Chamado quando usamos isset() ou empty()
public boolean offsetExists(mixed $offset)

// Chamado quando usamos empty()
// NOTA: Só é chamado quando ArrayAccess::offsetExists() retorna true
public mixed offsetGet (mixed $offset)

// Chamado quando usamos $obj['index'] = 'teste'
public void offsetSet(mixed $offset, mixed $value)

// Chamado quando usamos unset()
// NOTA: Fazendo casting para (unset) não chama esse método
public void offsetUnset(mixed $offset)

É isso, espero que tenham gostado!
Não esqueçam de comentar e de ler a documentação, RTFM.

http://br3.php.net/manual/pt_BR/class.arrayaccess.php