<?php
class Collection {

   private $_members = array();    // elementy kolekcji

   private $_onload;               // funkcja zwrotna

   private $_isLoaded = false;     // flaga okrelajca, czy funkcja zwrotna
                                   // zostaa ju wywoana

   public function addItem($obj, $key = null) {
      $this->_checkCallback();     // _checkCallback zdefiniowano nieco pniej

      if($key) {
         if(isset($this->_members[$key])) {
            throw new KeyInUseException("Klucz \"$key\" jest ju zajty!");
         } else {
            $this->_members[$key] = $obj;
         }
      } else {
         $this->_members[] = $obj;
      }
   }

   public function removeItem($key) {
      $this->_checkCallback();

      if(isset($this->_members[$key])) {
         unset($this->_members[$key]);
      } else {
         throw new KeyInvalidException("Bdny klucz \"$key\"!");
      }
   }

   public function getItem($key) {
      $this->_checkCallback();

      if(isset($this->_members[$key])) {
         return $this->_members[$key];
      } else {
         throw new KeyInvalidException("Bdny klucz \"$key\"!");
      }
   }

   public function keys() {
      $this->_checkCallback();
      return array_keys($this->_members);
   }

   public function length() {
      $this->_checkCallback();
      return sizeof($this->_members);
   }

   public function exists($key) {
      $this->_checkCallback();
      return (isset($this->_members[$key]));
   }

   /**
    * Ta metoda pozwala na zdefiniowanie funkcji,
    * ktr naley wywoa, aby wypeni kolekcj.
    * Jedynym parametrem tej funkcji powinna by
    * kolekcja do wypenienia.
    */
   public function setLoadCallback($functionName, $objOrClass = null) {
      if($objOrClass) {
         $callback = array($objOrClass, $functionName);
      } else {
         $callback = $functionName;
      }

      // sprawdzenie, czy funkcj zwrotn da si wywoa
      if(!is_callable($callback, false, $callableName)) {
         throw new Exception("Funkcja zwrotna $callableName nieprawidowa!");
         return false;
      }
      $this->_onload = $callback;
   }
   /**
    * Sprawdzenie, czy funkcja zwrotna zostaa zdefiniowana,
    * a jeli tak, czy zostaa ju wywoana. Jeli nie,
    * zostaje ona wywoana.
    */
   private function _checkCallback() {
      if(isset($this->_onload) && !$this->_isLoaded) {
         $this->_isLoaded = true;
         call_user_func($this->_onload, $this);
      }
   }
}
?>