Podana poniżej klasa ułatwia zarządzanie grupami obiektów. Zwraca instancje obiektów do użycia wewnątrz metod i funkcji - odpada $GLOBALS i global. Wersja rozwojowa. Przyszłościowo można zintegrować z rozwiązaniem __autoload.
Klasa korzysta z Reflection API dostępnym tylko w php5 oraz z niektórych metod dostępnych od wersji 5.1.3. Jest możliwe przerobienie tego na kod bardziej uniwersalny ( przy użyciu np. eval ) ale nie mam teraz czasu na to ( może w tygodniu znajdę czas ). Rozwiązując inaczej przekazywanie parametrów można obejść użycie metody newInstanceArgs.
Kod udostępniony na licencji GPL.
Kod klasy:
<?php /** * Manager Instancji. Tworzy oraz zarządza instancjami klas. * * @date 2006.07.01 * @author Grzegorz Drozd * @package ae */ class aeInstanceManager { /** * @var string nazwa właściwości klasy która decyduje czy jest to singleton czy
nie */ const SINGLE_PROPERTY_NAME= 'aeSingleton'; /** * @var bool domyślne traktowanie statusu klasy, w przypadku gdy dana klasa nie
ma ustawionego statusu */ const SINGLE_DEFAULT_VALUE= false; /** * @var string nazwa pola do którego należy wpisać nazwę instancji w gotowym obi
ekcie */ const INSTANCE_NAME_PROPERTY= 'aeInstance'; /** * @var array przechowuje instancje klas */ /** * Nie można tworzyć instancji tej klasy. */ final private function __construct() { } /** * Postawowa metoda klasy. Zwraca obiekt danego typu. * * Parametry klasy są całkowicie zmienne poza pierwszym. * Nie podanie nazwy instancji a wymaganie nowej instancji powoduje wygenerowani
e nazwy automatycznie na podstawie nazwy klasy oraz * microtime. * * * @param mixed $className string z nazwą klasy lub array z nazwą klasy oraz met
odą służącą do zwracania obiektu * * Akceptowalne parametry zmienne: * @param string nazwa instancji * @param bool true - zwraca singleton, false - zwraca nową instację * @param array argumenty do przekazania nowo tworzonej instacji */ self::checkVersion(); $single= aeClassManager :: SINGLE_DEFAULT_VALUE; $singleSet= false; //sprawdzenie jakie parametry zostały podane case 'string' : case 'integer' : break; case 'array' : break; case 'boolean' : // to do sprawdzenia czy podano taki argument wogóle. $singleSet= true; break; } } $methodName = $className[1]; $className = $className[0]; } //tworzenie nowej klasy Reflection $class= new ReflectionClass($className); //sprawdzenie statusu singletona $mustBeSingleton= self :: getPropertyValue($class, aeClassManager :: SINGLE_PROPERTY_NAME); //sprawdzenie czy argument $single jest poprawny w stosunku do własności klasy if (($mustBeSingleton != $single XOR $singleSet != true) AND $mustBeSingleton != null) { throw new Exception('Invalid argument, class: ' . $className. ($mustBeSingleton ? ' must be ' : " can't be ").'singleton'); } // jeżeli obiekt o takiej nazwie instancji jest już utworzony - zwróć go if (is_a(self :: $instances[$instanceName]['obj'], $className)) { return self :: $instances[$instanceName]; } // jeżeli nie podano nazwy instacji to przyjmij nazwę klasy i jeżeli nie singleton
dodaj do niej czas $instanceName= $className . '_' . (self :: getMicrotime()); } else { } // jeżeli wymagamy singletona - szukamy go - jeżeli nie to idziemy dalej if ($mustBeSingleton == true AND ($retClass= self :: getInstancesOfObject($className, 1) !== false)) { return $retClass['obj']; } // utowrzenie instancji klasy - poprzez odpowiednią metodę $m = $class->getMethod($methodName); //jeżeli nie przekazano argumentów to tworzy prostą instację self :: $instances[$instanceName]['obj'] = $m->invoke( ($m->isStatic() ? NULL : $class) ); //lub przekazuje parametry } else { self :: $instances[$instanceName]['obj'] = $m->invokeArgs(($m->isStatic() ? NULL : $class), $arguments); } // lub konstruktor } else { //jeżeli nie przekazano argumentów to tworzy prostą instację self :: $instances[$instanceName]['obj']= $class->newInstance(); //lub przekazuje argumenty } else { self :: $instances[$instanceName]['obj']= $class->newInstanceArgs($arguments); } } // jeżeli obiekt posiada odpowiednie pole - ustaw w nie nazwę instancji. if ($class->hasProperty(aeClassManager :: INSTANCE_NAME_PROPERTY) ) { $varName = aeClassManager::INSTANCE_NAME_PROPERTY; self :: $instances[$instanceName]['obj']->$varName = $instanceName; } //ustawienie nazwy obiektu do tabeli instances - szybsze wyszukiwanie self :: $instances[$instanceName]['type']= $className; return self :: $instances[$instanceName]['obj']; } /** * Zwraca listę przechowywanych instancji. * * @return array lista instancij */ return self :: $instances; } /** * Metoda zwraca tablicę obiektów podanego typu. * * @param string $objName nazwa obiektu do znalezienia na liście * @param num $limit limit zwróconych obiektów danego typu * @return array lista znalezionych obiektów */ $n= 0; foreach (self :: $instances as $key => $val) { if ($val['type'] == $objName) { $ret[]= $val; $n++; if ($limit != null AND $limit == $n) { break; } } } } /** * @ignore * @internal klasa wewnętrzna tylko do tworzenia unikalnych nazw instancji */ return ((float) $usec + (float) $sec); } /** * Funkcja zwraca z podanego obiektu typu ReflectionClass wartość pola bez wzglę
du na to * czy to pole statyczne czy też pole normalne (wtedy ZWRACA WARTOŚĆ DOMYŚLNĄ OBIEKTU ! * a nie zmienioną - czyli taką jak w definicji obiektu) * * @param ReflectionClass $class klasa z której pobierane są właściwości * @param string $property nazwa właściwości do zwrócenia * @return mixed wartość właściwości */ if ($class->hasProperty($property)) { $rp= $class->getProperty($property); if ($rp->isStatic()) { return $class->getStaticPropertyValue($property); } $ar= $class->getDefaultProperties(); return $ar[$property]; } return null; } /** * Metoda używana w destruktorach do usuwania instancji z list * * @todo dokończyć - nie działa * @param string $instanceName nazwa instancji do usunięcia */ } throw new Exception('Incorect php version! You must use at least 5.1.3'); } } } ?>
Przykłady użycia:
<?php require_once 'aeInstanceManager.class.php'; class someSingletonClass{ public function __construct(){ } } class thisObjectCantBeSingleton{ public $aeSingleton = false; public function __construct(){ } } class thisIsNormalObject{ public $aeInstance; public function __construct() { } public function __destruct() { aeClassManager::destroyInstance($this->aeInstance); } } class singleton{ public $aeSingleton = true; private function __construct(){ } if (self::$instance == null){ $class = __CLASS__; self::$instance = new $class; } return self::$instance; } } //singleton - bez parametrów - kontroler zczytuje z pola w klasie $obj1 = aeClassManager::getInstance('someSingletonClass'); $obj1 = aeClassManager::getInstance('someSingletonClass'); //tworzenie przez wywołanie specjalnej metody - działa na singletony i normalne klasy - np. db //ten obiekt nie może być singletonem - dodanie parametru true wywoła wyjątek //parametry - poza 1szym - mogą być podawane w dowolnej kolejności $obj4 = aeClassManager::getInstance('thisIsNormalObject', 'siakisObiekt1', false); $obj5 = aeClassManager::getInstance('thisIsNormalObject', false, 'siakisObiekt2'); //ten obiekt zostaje singletonem - wywołanie go z tymi samymi parametrami zwróci cały czas ten sam obiekt $obj6 = aeClassManager::getInstance('thisIsNormalObject', true, 'siakisObiekt'); $obj6 = aeClassManager::getInstance('thisIsNormalObject', true, 'siakisObiekt'); ?>