getHash( $element ); $position = count( $this->elements ); $this->elements[] = $element; $this->indexHash[$hash][] = $position; } public function addAll( iCollection $collection ) { foreach( $collection as $element ) { $this->add( $element ); } } public function remove( $element ) { $hash = $this->getHash( $element ); if( ! $this->contains( $element ) ) { return false; } $position = array_pop( $this->indexHash[$hash] ); if( empty( $this->indexHash[$hash] ) ) { unset( $this->indexHash[$hash] ); } unset( $this->elements[$position] ); return true; } public function removeAll( iCollection $collection ) { $result = false; foreach( $collection as $element ) { $result |= $this->remove( $element ); } return $result; } public function contains( $element ) { return array_key_exists( $this->getHash( $element ), $this->elements ); } public function retainAll( iCollection $collection ) { $result = false; foreach( $this->elements as $ownItem ) { if( !$collection->contains( $ownItem ) ) { $result |= $this->remove( $ownItem ); } } return $result; } public function isEmpty() { return empty( $this->elements ); } public function count( ) { return count( $this->elements ); } public function rewind() { reset($this->elements); } public function current() { return current($this->elements); } public function key() { return key($this->elements); } public function next() { return next($this->elements); } public function valid() { return $this->current() !== false; } } class Set extends Collection implements iSet { public function add( $element ) { if ( $this->contains( $element ) ) { throw new ElementAlreadyExistingException( 'Element already existing' ); } parent::add( $element ); } } class ElementAlreadyExistingException extends Exception { } class ElementNotPresentException extends Exception { } class TypeConstraintViolationException extends Exception { } final class TypeSafeDelegate { private $type; const INT = '#integer'; const STRING = '#string'; const BOOL = '#boolean'; const FLOAT = '#float'; private function requiresPrimitiveType( ) { return $this->type{0} == '#'; } public function initType( $type ) { $this->type = $type; } private function assertType( $element ) { $isObj = is_object( $element ); $isPri = $this->requiresPrimitiveType(); if( $isObj XOR $isPri ) { throw new TypeConstraintViolationException( 'Either received a primitive type and expected an object or received an object and expected a primary type'); } if( $isObj && ! is_a( $element, $this->type ) ) { throw new TypeConstraintViolationException( 'Element is not an instance or subclass of ' . $this->type .', '. get_class( $element ).' given.'); } if( $isPri ) { $priType = substr( $this->type, 1 ); $function = 'is_' . $priType; if( !$function( $element ) ) { throw new TypeConstraintViolationException( 'Element is not a '.$priType.', '. gettype( $element ).' given.'); } } } } class TypesafeSet implements iSet { private $set; private $checker; public function __construct( $typename ) { $this->set = new Set( ); $this->checker = new TypeSafeDelegate(); $this->checker->initType( $typename ); } public function add( $element ) { $this->checker->assertType( $element ); $this->set->add( $element ); } public function has( $element ) { $this->set->has( $element ); } // ... } ?>