Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Własna wersja klasy Singleton, dla wzorca Singletonu
Forum PHP.pl > Forum > PHP > Object-oriented programming
likemandrake
Witam

Na tyle ile możliwości ma PHP w tej dziedzinie napisałem własną wersję klasy Singleton dla wzorca Singletonu, zamieszczając ją tutaj na forum chciałbym uzyskać troche opinii i propozycji odnośnie mojego rozwiązania smile.gif

  1. <?php
  2.  
  3. abstract class Singleton {
  4. private static $aInstances = array();
  5.  
  6. final protected function __construct(&$aArguments) {
  7. call_user_func_array(array($this, '__initialize'), $aArguments);
  8. }
  9. protected function __initialize() {
  10.  
  11. }
  12. final public function __clone() {
  13. trigger_error("Cloning of class '" . get_class($this) . "' is not allowed", E_USER_ERROR);
  14. }
  15. final public static function getInstance($sClassName) {
  16. if(!isset(self::$aInstances[$sClassName])) {
  17. $aArguments =& func_get_args();
  18. array_shift($aArguments);
  19. self::$aInstances[$sClassName] = new $sClassName($aArguments);
  20. }
  21. return self::$aInstances[$sClassName];
  22. }
  23. }
  24.  
  25. ?>


Gdzieś czytałem, że nie zaleca się rozpoczynać nazw metod od dwóch podkreślników, gdyż koliduje to z ogólnie przyjętym schematem nazewnictwa metod magicznych oraz konstruktora i destruktora w PHP. Jeśli też tak uważacie, proszę o propozycję ładnej nazwy angielskiej tejże metody smile.gif

Przykład użycia:
  1. <?php
  2.  
  3. require_once './class.Singleton.php';
  4.  
  5. class Example extends Singleton {
  6. private $sParam;
  7.  
  8. protected function __initialize($sParam) {
  9. $this->sParam = $sParam;
  10. }
  11. public function __toString() {
  12. return $this->sParam;
  13. }
  14. }
  15.  
  16. $oFirstExample = Example::getInstance('Example', "Parametr przekazany do konstruktora");
  17. // lub też Singleton::getInstance('Example', ...
  18.  
  19. $oSecondExample = Example::getInstance('Example');
  20.  
  21. echo $oFirstExample . '<br>';
  22. echo $oSecondExample;
  23.  
  24. ?>


Pozdrawiam
sobstel
Moim zdaniem składnia typu Example::getInstance('Example') to programistyczne masło maślane. Równie dobrze moge wywołać Singleton::getInstance('Example') czy też Example::getInstance('jakakolwiek klasa'). Uważam, że trzeba się pogodzić z tym, że PHP (w wersji < 5.3) przy wywoływaniu metod statycznych odwołuje się do ojca, a nie dziecka i w klasach pochodnych ponownie definiować getInstance() itp. albo po prostu używać np. rejestru Registry::getInstance('class name') czy czegoś w tym stylu (i spokojnie czekać na PHP 5.3). Właściwie Twoje rozwiązanie przypomina bardziej wzorzec Registry ;-)

Po co __initialize? w tym celu jest __construct przecież.
likemandrake
No właśnie, to czekanie jest najgorsze, a do tej pory trzeba sobie jakoś radzić smile.gif

Czemu __initialize? Generalnie może zdarzyć się tak, że mimo to iż dziedziczę po wzorcu Singleton (może nie koniecznie bezpośrednio, ale w którejś podklasie z kolei) może się zdarzyć tak, że przypadkowo przeładuje konstruktor na publiczny, a jest to możliwe. Szkoda, że nie ma w PHP wymuszenia używanego dostępu do zmiennej bądź klasy smile.gif Ten problem postanowiłem więc rozwiązać w taki sposób jak widać.

Innym ciekawym rozwiązaniem byłoby zastosowanie AspectPHP, gdyby to istniejące projekty byłyby zadowalająco dobrze napisane, a tak to trzeba się męczyć. Dzięki AspectPHP taki Singleton możnaby uzyskać automatycznie.

Dość interesującym projektem jest wtyczka do Eclipse - APDT, która bazuje trochę na PHPAspect (chyba napisana przez tych samych autorów) lecz PHPAspect jest napisany w PHP i niestety nie grzeszy wydajnością. A wracając do APDT, jest to projekt, który jeszcze nie wyszedł po za repozytoria SVN, jednak zapowiada się wspaniale smile.gif
empathon
Jeśli tworzysz sobie klasę abstract Singletona rozumiem, że będziesz jej używał gdzie się da? Tylko niestety singleton przeczy zasadą OOP, tworzy niepotrzebne "węzełki" w kodzie. Popracuj nad workflow obiektów a nie twórz takie potworki.
Jestem też ciekaw co Ci daje wywołanie zdefiniowanej funkcji w konstruktorze kiedy nie ma ona żadnego dostępu do metod i parametrów klasy.
Przemyśl dobrze co napisałeś.
likemandrake
Cytat(empathon @ 8.06.2008, 13:01:12 ) *
Jestem też ciekaw co Ci daje wywołanie zdefiniowanej funkcji w konstruktorze kiedy nie ma ona żadnego dostępu do metod i parametrów klasy.
Przemyśl dobrze co napisałeś.



Czy mógłbym Cię prosić o rozwinięcie swojej myśli? Chciałbym być pewien tego co rozumiem z Twojej wypowiedzi smile.gif

Z góry wielkie dzięki za poświęcony czas.
empathon
Cytat(likemandrake @ 8.06.2008, 13:37:51 ) *
Czy mógłbym Cię prosić o rozwinięcie swojej myśli? Chciałbym być pewien tego co rozumiem z Twojej wypowiedzi smile.gif

Z góry wielkie dzięki za poświęcony czas.

Ok, źle przeczytałem kod. Ale nadal nie widzę sensu dla metody __initialize. Skoro nie pozwalasz nadpisać __construct, tym samym nadpisujesz __initialize to jest on tu tylko niepotrzebnym mostem. Rozumiem ochronę konstruktora jeśli byłoby tam coś jeszcze ale tu... W dodatku wymuszasz istnienie metody __initialize a jednocześnie nie ma tu żadnego interface'u. Konstruktor jest właściwą metodą do inicjacji.
likemandrake
Wiesz, specjalnie nie tworzylem abstrakcyjnej metody __initialize, bo pewnie nie zawsze bedzie mi potrzeba zrobic cos podczas powolywania obiektu do zycia. Z drugiej strony... chyba jednak pasowaloby dac to slowko abstract przed __initialize smile.gif

A piszac bardziej profesjonalnie, rzeczywiscie jest tak, ze do inicjacji jest konstruktor, tylko dla mnie problemem jest to, ze moge sobie w klasie pochodnej zmienic uprawnienia konstruktora (przypadkowo), np. na publiczne i szlag by trafil Singletona. Nie znam sposobu w PHP (i chyba ogolnie tak w OOP sie nie da), zeby wymusic na klasach pochodnych przeladowywanie konstruktora na konkretny sposob dostepu do niego (public, protected, private).

Co radzisz mistrzu? biggrin.gif
dr_bonzo
Co do __initialize to sie zgadzam, i mozna tak robic, z wyzej wymienionych powodow [wzorzec templateMEthod, + nie mamy mozliwosci nadpisania konstruktora w podklasach].

A klasa jako ogol - totalny bezsens, singleton to zlo, i jest zaprzeczeniem OOP, to jest po prostu global ukryty w klasie. Ze wszystko ma byc singletonem? masakra. W moim FW + libie do DB jest.... 1 singleton, ciezko bylo by mi sie bez niego obejsc, jest to glowna klasa biblioteki baz danych, przez ktora pobieram bierzace polaczenie z baza. Niby mozna to inaczej zrobic, ale skonczy sie na

$user = $this->DB_manager->newInstanceForClass( 'User' );

ktore przekaze instancje polaczenia. Gore wziela wygoda pisania niz calkowicie czyste oop smile.gif
likemandrake
Generalnie, rzeczywiscie niewiele byloby klas, ktorych instancji nie chcielibysmy miec wiecej niz jednej. Do takich klas możnaby wg mnie zaliczyc klase do obslugi bazy danych, do obslugi sesji, do obslugi autoryzacji, do obslugi systemu szablonow, do obslugi bledow (set_error_handler), itp.

Tak więc, czy ktoś zrobi sobie klasę do tego typu przypadków, czy po prostu utworzy odpowiedni interfejs, to już chyba zależy od indywidualnych potrzeb. Nawet w książkach o zaawansowanym programowaniu w PHP często pojawia się wzorzec Singletonu i nie jest on w żaden negatywny sposób krytykowany, jest to więc wzorzec powszechnie używany nawet przez zaawansowanych programistów. Co czasem jest niezgodne z OOP nie znaczy, że jest bez sensu i do kitu, prawda?

A jak się widzi użycie interfejsu iSingleton questionmark.gif smile.gif
empathon
Przeczytaj sobie to: http://blog.dywicki.pl/2007/02/01/singleton/
likemandrake
W takim razie, czy zamiast tego, można używać wzorca rejestru? Czy to też taki anty-wzorzec?
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.