Location: PHPKode > scripts > Collection > collection/Collection.class.php
<?php

 /*****************************************************************************
 *
 * Class Name : Collection
 * Version    : 1.6
 * Written By : Diogo Souza da Silva <hide@address.com>
 * License: GPL
 *
 ******************************************************************************
 *
 * This class implements Collection object in PHP. Some things you should know.
 * This class can behave exactly like an array
 * It just work in PHP5
 * This class can(maybe should) be extendend
 * Only two entry points, add() and set()
 * Only one leaving point, remove()
 * This class implments Iterator and ArrayAccess
 * You can usi it in foreach, while and others just like an array
 * It is an iterator for itself also
 * You cannot extends ArrayObject and implements ArrayAccess
 * 
 *****************************************************************************
 * 
 * TODO: 
 * PHPDOC for real
 * Clean some functions
 * Make real tests, now it example file as test
 * Implement type safe Collection
 * Implement some kind of "lock" or "state"
 * Implement someway for applying a function to all elements
 * Improve __toXml and __toString
 * Create to __toJson?
 * More on SPL?
 * Implement Serializable(__wakeup and __sleep)?
 * Implement __get and __set for the Collection elements?
 * Maybe refactor the hole class for subclasses? (split method in classes)
 */

    
    class Collection implements Iterator , ArrayAccess  {
        
        /**
         * The number of elements in the Collection
         * @var int
         */
        public $lenght=0;
        /**
         * The inner array
         * @var array
         */
        private $elements = array();       

        /**
         * Create a collection of objects
         * @param array|collection $array [optional]
         */
        function __construct($array=null) {
            $this->merge($array,true);            
        }

        /**
         * Adds an object into collection
         * if arg1 only is given, it will be the item at last index
         * if arg1 and arg2 is given, arg1 will be the index(key) and arg2 will be the value
         * It does not "set" to an existing index, use set insted
         * @param mixed $ag1
         * @param mixed $arg2 [optional]
         * @return Collection
         */
        function add($arg1,$arg2=false)  {
            if(!$arg2) {
                $this->elements[] = $arg1;
            } else {
                if (!array_key_exists($arg1,$this->elements)) {
                    $this->elements[$arg1] = $arg2;
                }
            }
            $this->count();		
            return $this ;
        }
        
     /**
     * Set the value of the given key
     * @param key $key
     * @param mixed $item
     * @return mixed $item
     */
        function set($key,$item) {
	    if(isset($key)) {
		$this->elements[$key] = $item;
            } else {
		$this->elements[] = $item ;
	    }
            $this->count();
            return $this->get($key);
        }
    
    /**
     * Adds value at last index
     * @param $value
     * @return Collection
     */
        function append($value) {
            return $this->add($value);
            //return $this ;
        }
    
        /**
         * Join(merge) an array or a collection into this one
         * @param array|collection $array
         * @param bool $keepkeys
         * @param bool $overload
         * @return Collection
         */
        function merge($array,$keepkeys=false,$overload=false) {
            if(is_array($array) or $array instanceof ArrayAccess) {
                //$this->elements = array_merge($this->elements,$array);
                if(count($array) >= 1)
                  foreach($array as $k=>$v) {
                      if($keepkeys) {
                          if($overload)
                           { $this->set($k,$v);}
                          else
                            {$this->add($k,$v);}
                      } else {
                        $this->add($v);
                      }
                  }
            } else if($array instanceof Iterator) {
                //$this->elements = array_merge($this->elements,$array->getArrayCopy());
                while($array->valid()) {
                      if($keepkeys) {
                        if($overload)
                          {$this->set($array->key(),$array->current());            }        
                        else
                          {$this->add($array->key(),$array->current());             }
                      }else{
                        $this->add($array->current());
                      }
                    $array->next();
                }
            }
            $this->count();		
                
            return $this ;
        }
        
    /**
     * Sort by values, keeping keys
     * @param CONST flags
     * @return Collection
     */
        function asort($flags=null) {
            asort($this->elements,$flags);
            return $this;
        }
        
        /**
         * Sort by key
	 * @param CONST flags
	 * @return Collection
         * 
         */
        function ksort($flags=null) {
            ksort($this->elements,$flags);
            return $this;
        }
        /**
         * sort by natural order
	 * @param CONST flags
	 * @return Collection
         */
        function sort($flags=null) {
            sort($this->elements,$flags);
            return $this ;
        }
        
        /**
         * size number of itens;
         * @return int
         */
        function count() { 
            $this->lenght = count($this->elements);
            return $this->lenght ;
        }        
        
        /**
         * Remove the $key item
         * @param key $key
         * @return Collection
         */
        function remove($key) {
            if (array_key_exists($key,$this->elements)) {
                unset($this->elements[$key]);
                $this->count();
                return $this;
            }
        }

        /**
         * Verifies if this key is filled
         * @param key $k
         * @return bool
         */
        function exists($k) {
            return array_key_exists($k, $this->elements);
        }

        /**
         * Moves the cursor a step foward
         * @return bool
         */
        function next() {
            return next(&$this->elements) ;
        }
        /**
         *  If next element is valid
         * @return bool
         */
        function hasNext() {
            $this->next() ;
            $v = $this->valid() ;
            $this->back() ;
            return $v ;
        }
    
    /**
     * Moves cursor to given key
     * @param key $key
     * @return bool
     */
        function seek($key) {
            $this->rewind();
            while($this->valid()) {
                if($this->key() == $key) {
                    return true;
                }
                $this->next();
            }
            return false;
        }
        
        /**
         * Moves the cursor a step back
         * @return bool
         */
        function back() {
            return prev(&$this->elements);
        }

        /**
         * Puts the cursor at start
         * @return bool
         */
        function rewind() {
            return reset(&$this->elements);
        }

        /**
         * Puts cursor at the end
         * @return bool
         */
        function forward() {
            return end(&$this->elements);
        }

        /**
         * Return the item in the cursor point
         * @return mixed Current Item
         */
        function current() {
            return current($this->elements);
        }
    
    
    /**
     * Returns cursor key
     * @return mixed current key
     */
        function currentKey() {
            return key($this->elements) ; 
        }
    
    /**
     * Actual cursor key
     * @return mixed current key
     */
        function key() {
            return $this->currentKey();
        }
        
        /**
         * Check if cursor is at a valid item
         * @return bool
         */
        function valid() {
            if(!is_null($this->key())) {
                return true;
            } else {
                return false ;
            }
        }
        
        /**
         * same as valid()
         * @return bool
         */
        function isValid() {
            return $this->valid();
        }
        
        /**
         * Returns object for given posistion
         * @param key $key
         */
        function get($key) {
            return $this->elements[$key];
        }
        
        /**
         * Fetchs basic 
         */
        
        function fetch() {
            if($this->valid()) {
              $r = $this->current();
              $this->next() ;
              return $r ;
            } else {
                return false;
            }
        }
    
   
    /**
     * ArrayAccess, check if offset (key) exists
     * @param $offset
     * @return bool
     */
        function offsetExists($offset) {
            return $this->exists($offset);
        }
    /**
     * ArrayAccess, get element
     * @param $offset
     * @return mixed 
     */
        function offsetGet($offset) {
            return $this->get($offset);
        }
    /**
     * ArrayAccess, set element
     * @param key $offset
     * @param mixed $value
     * @return mixed
     */
        function offsetSet($offset,$value) {
            return $this->set($offset, $value);
        }
    /**
     * ArrayAccess, remove element
     * @param key $offset
     * @return COllection $this
     */
        function offsetUnset($offset) {
            return $this->remove($offset);
        }
	
    /**
     * Null all the collection, including keys
     * @return Collection $this;
     */
    function clear() {
	$this->elements = array();
	$this->length = 0;
	return $this ;
    }
    
    /**
     * @return the size of the collection
     */
    function size() {
	return $this->count();
    }
    
    /**
     * returns if the collection is empty or not
     * @return bool
     */
    function isEmpty() {
	if($this->count() < 1)
        	return true ;
	else
                return false;
    }
    
    /**
     * Check if given object exists in collection
     * Type safe
     * @param mixed $obj
     * @return bool
     */
        function contains($obj) {
            foreach($this->elements as $element) {
                if($element === $obj) {
                    $this->rewind();
                    return true ;
                }
            }
            $this->rewind();
            return false ;
        }
    
    /**
     * Return the (first) index(key) of given object
     * @param mixed $obj
     * @return key of the obj
     */
        function indexOf($obj) {
            foreach($this->elements as $k=>$element) {
                if($element === $obj) {    			
                    $this->rewind();
                    return $k ;
                }
            }
            $this->rewind();
            return null ;
        }
    
    /**
     * returns last index(key) of given object
     * @param mixed $obj
     * @return key
     */
        function lastIndexOf($obj) {
            $return = null ;
            foreach($this->elements as $k=>$element) {
                if($element === $obj) {
                    $return =  $k ;
                }
            }
            $this->rewind();
            return $return ;
        }
    
    /**
     * Return a new collection with a part of this collection
     * @param int $start
     * @param int $end
     * @return Collection 
     */
        function subCollection($start,$end) {
            $new = new Collection();
            $i = 0;
            foreach($this->elements as $k=>$element) {
                if($i <= $end && $i >= $start) {
                    $new->add($element) ;
                }
                $i++ ;
            }
            $this->rewind();
            return $new ;
        }
    
    /**
     * Cut the array to given size
     * @param int $size
     * @return Collection
     */
        function trimToSize($size) {
            $t = array_chunk($this->elements,$size,true);
            $this->elements = $t[0];
            $this->count();
            return $this ;
        }

    /**
     * Return the xml of this collection
     * @return string
     */
        function __toXml() {
            $xml = "\n<Collection>";
            foreach($this->elements as $k=>$v) {
                $xml .= "\n\t<element key=\"{$k}\">";
                if(is_string($v)) {
                    $xml.= $v ; 
                } else if(is_object($v) and method_exists($v,"__toXml()")) {
                    $xml.= $v->__toXml() ; 				
                } else if(is_object($v) and method_exists($v, "__toString()")) {
                    $xml.= $v->__toString() ; 				
                }
                $xml .= "</element>";
            }
            $xml .= "\n</Collection>";
            $this->rewind();
            return $xml ;
        }
    
    /**
     * A alias to __toXMl()
     * @return $string
     */
    function toXML() {
	return $this->__toXML();
    }
    
    /**
     * Returns as an array
     * @return array
     */
    function __toArray() {
	return $this->elements ;	
    }
    
    /**
     * A alias to __toArray()
     * @return array
     */
    function toArray() {
	return $this->__toArray();
    }
    
    /**
     * Alias to toArray()
     * @return array
     */
    function asArray() {
	return $this->toArray();
    }

    /**
     * NOT WORKING YET
     */
     function getIterator() {
	 return $this ;
     }
    /**
     * Alias to toArray()
     * @return array
     */
        
    function getArrayCopy() {
	return $this->toArray() ;
    }
    
    /**
     * serialize the collection
     * @return string
     */
        function __toString() {
            return "".serialize($this->elements)."" ;
        }
    
    /**
     * alias to __toString()
     * @return string
     */
        function toString() {
            return $this->__toString();
        }
        
    }
?>
Return current item: Collection