Stworzyłem sobie klasę koszyka i klasę produktu. Dla wygodnego wyświetlania zawartości koszyk implementuje interfejs Iterator i tutaj pojawia się dziwnym problem. Gdy dodam kilka produktów do koszyka wszystko działa, pętla foreach poprawnie wyświetla produkty ale jak usunę tylko jeden produkt to w pętli już nic się nie wyświetla. Oto cały kod:

<?php

class CartProduct {
	
	private $id;
	private $quantity;
	
	public function __construct($id, $quantity) {
		$this->id = $id;
		$this->setQuantity($quantity);
	}
	
	public function id() {
		return $this->id;
	}
	
	public function setQuantity($quantity) {
		$q = (int)$quantity;
		$this->quantity = $q < 0 ? 0 : $q;
		return $this;
	}
	
	public function increaseQuantity($value) {
		$v = (int)$value;
		$this->setQuantity($this->quantity() + $v);
		return $this;
	}
	
	public function decreaseQuantity($value) {
		$v = (int)$value;
		$this->setQuantity($this->quantity() - $v);
		return $this;
	}
	
	public function quantity() {
		return $this->quantity;
	}
	
	public function equals(CartProduct $product) {
		return $this->id == $product->id;
	}
	
	public function append(CartProduct $product) {
		if($this->equals($product)) {
			$this->increaseQuantity($product->quantity());
		}
		return $this;
	}
}

class Cart implements Iterator {
	
	private $products = array();
	private $cursor = 0;
	
	public function add(CartProduct $product) {
		if(($existingProduct = $this->search($product))) {
			$existingProduct->append($product);
		} else {
			$this->products[] = $product;
		}
		return $this;
	}
	
	public function remove(CartProduct $product) {
		$tmp = array_filter($this->products, function($p) use ($product){
			return !$p->equals($product);
		});
		$this->products = $tmp;
		return $this;
	}
	
	public function search(CartProduct $product) {
		foreach($this as $p) {
			if($p->equals($product)) return $p;
		}
		return false;
	}
	
	public function current() {
		return isset($this->products[$this->cursor]) ? $this->products[$this->cursor] : null;
	}
	
	public function key() {
		return $this->cursor;
	}

	public function next() {
		$row = $this->current();
		$this->cursor++;
		return $row;
	}
	
	public function rewind() {
		$this->cursor = 0;
	}
	
	public function valid() {
		return (!is_null($this->current()));
	}
	
}

$cart = new Cart();
$p1 = new CartProduct(1, 10);
$p2 = new CartProduct(2, 20);
$p3 = new CartProduct(3, 30);

$cart->add($p1)->add($p2)->add($p3);
foreach($cart as $p) { //ta petla dziala
	var_dump($p);
}

$cart->remove($p1);
foreach($cart as $p) { //ta nie dziala
	var_dump($p);
}