Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Jedna instancja klasy zamiast wielu - singleton
Forum PHP.pl > Forum > PHP > Object-oriented programming
Joachim Peters
Witam,

Zastanawiam się czy da się jakoś inaczej stosować singleton niż tak:
  1. <?php
  2. $db = DB::getInstance();
  3. $user = User::getInstance();
  4. $session = Session::getInstance();
  5. ?>

Czy jest jakiś krótszy sposób? Jak robicie to u siebie, referencję? Bo to jest trochę męczące, żeby dodawać ten kod w każdej metodzie.

Pozdrawiam
Cysiaczek
Ja robię najczęściej referencję, ale nie zawsze - zależy jak mi wygodniej, czasem przekazuję obiekt jako parametr

Pozdrawiam.
Joachim Peters
Może ktoś zarzuci jakiś przykład?
qoob
ja mam ten sam problem i teraz wymyslilem cos takiego:
  1. <?php
  2. class GetClass {
  3. private $class = array();
  4.  
  5. static public $oInstance = false;
  6. public static function gi() {
  7.  
  8. if( self::$oInstance == false ) {
  9. self::$oInstance = new GetClass;
  10. };
  11.  
  12. return self::$oInstance;
  13.  
  14. }
  15.  
  16.  
  17. public function createObj($obj,$name = FALSE) {
  18.  
  19. if(!$name) {
  20. $name = $obj;
  21. }
  22.  
  23. $name = strtolower($name);
  24. $this->class[$name] = new $obj;
  25.  
  26.  
  27. }
  28.  
  29.  
  30. public function addObj($refToObj,$name = FALSE) {
  31.  
  32. if(!$name) {
  33. $name = get_class( $refToObj );
  34. }
  35.  
  36. $name = strtolower($name);
  37.  
  38. $this->class[$name] = $refToObj;
  39. }
  40.  
  41.  
  42. public function __get($objName) {
  43.  
  44. return $this->class[ strtolower($objName) ];
  45. }
  46.  
  47. }
  48.  
  49.  
  50.  
  51.  
  52. class Q {
  53. public $text;
  54. }
  55.  
  56.  
  57. $gc = GetClass::gi();
  58.  
  59. $gc->createObj('Q');
  60. $gc->q->text = 'hello hello';
  61. echo $gc->q->text;
  62.  
  63.  
  64. ?>



wtedy tylko jedna klasa jest singielem a reszta juz nie musi byc. nie wiem czy to dobry sposob, bo jak by nie patrzec zawsze jeden antywzorzec zostaje, ale plusem jest to ze we wszystkich innych klasach ktore powinny miec tylko jeden obiekt mozna pominac statyczny fragnent kodu.
pozdrawiam
Joachim Peters
Ja stworzyłem coś takiego, może już jest taki wzorzec, ale to rozwiązanie mi się podoba:
  1. <?php
  2.  
  3. class Kernel {
  4. public $foo;
  5.  
  6. static $instance;
  7.  
  8. public function __construct() {
  9. $this->foo = new Foo;
  10. }
  11.  
  12. public static function getInstance() {
  13. if(!self::$instance) {
  14. self::$instance = new Kernel;
  15. }
  16. return self::$instance;
  17. }
  18. }
  19.  
  20. class Foo {
  21. public function a($string) {
  22. echo $string;
  23. }
  24. }
  25.  
  26. class Foo2 {
  27. public function b() {
  28. $kernel = Kernel::getInstance();
  29. $kernel->foo->a('test');
  30. }
  31. }
  32.  
  33. $foo2 = new Foo2;
  34. $foo2->b();
  35.  
  36. ?>


Wystarczy zadeklarować instancję w konstruktorze jajka i działa smile.gif
Ludvik
Problemem tego kodu jest fakt, że możesz utworzyć dowolną liczbę instancji każdej ze zdefiniowanych klas. Klasa Kernel ma publiczny konstruktor, a pozostałe nie definiują, czyli posiadają domyślny (który też jest publiczny...). Poza tym - publiczne składowe też nie sprzyjają zachowaniu spójności obiektu. Z dowolnego miejsca możesz nadpisać wartość atrybutu i zrobi się bałagan.
Joachim Peters
Wiedziałem, że to nie jest idealne, dlatego czekam na propozycję jakiejś mądrzejszej osoby.
NuLL
Cytat(Cysiaczek @ 28.07.2007, 17:45:59 ) *
Ja robię najczęściej referencję, ale nie zawsze - zależy jak mi wygodniej, czasem przekazuję obiekt jako parametr

Pozdrawiam.

W PHP5 obiekty zawsze sa przekazywane przez referencje party.gif
Cysiaczek
eee NuLL ; ]
Odpowiadałem na pytanie:
Cytat
Czy jest jakiś krótszy sposób? Jak robicie to u siebie, referencję? Bo to jest trochę męczące, żeby dodawać ten kod w każdej metodzie.


Chodziło mi o lokalną referencję, czy to w obiekcie, czy w funkcji.

Pozdrawiam.
Ludvik
Kompozycja jest zwykle najlepszym wyjściem...

Osobiście nie spotkałem się z sytuacją, w której musiałbym korzystać z Singletonu/Rejestru do pobrania instancji obiektu. Wszystko trafia albo do konstruktora, albo jako argument metody, albo leci w jakimś kontenerze (np. w czasie wykonywania łańcucha akcji). Singleton ogólnie nie sprzyja testom jednostkowym, gdyż wprowadza zależność, której nie zlikwidujesz raczej bez modyfikacji kodu.
Joachim Peters
Rozumiem, że chodzi o coś takiego?
  1. <?php
  2.  
  3. class Foo {
  4. private $db;
  5.  
  6. public function __construct($db) {
  7. $this->db = $db;
  8. }
  9.  
  10. public function a() {
  11. $this->db->query('zapytanie');
  12. }
  13. }
  14.  
  15. $db = new DB();
  16. $foo = new Foo($db);
  17.  
  18. ?>


Ps Dziękuje @Ludvik za zainteresowanie!
Ludvik
Cytat(Joachim Peters @ 1.08.2007, 22:19:30 ) *
Rozumiem, że chodzi o coś takiego?
  1. <?php
  2.  
  3. class Foo {
  4. private $db;
  5.  
  6. public function __construct($db) {
  7. $this->db = $db;
  8. }
  9.  
  10. public function a() {
  11. $this->db->query('zapytanie');
  12. }
  13. }
  14.  
  15. $db = new DB();
  16. $foo = new Foo($db);
  17.  
  18. ?>


Ps Dziękuje @Ludvik za zainteresowanie!

Nie ma problemu smile.gif Dokładnie o to chodzi smile.gif Do tego możesz wymusić kontrolę typów, dzięki czemu zachowasz spójność obiektu. Zauważ, że przy testach jednostkowych klasy Foo likwidujesz skutki działania obiektu klasy DB. Po podstawieniu mocka test zostanie zaliczony, nawet gdy klasa DB nie przechodzi swoich testów. Singleton wymuszałby użycie konkretnej klasy, która niekoniecznie działa prawidłowo (o ile została już zaimplementowana).
Joachim Peters
Cytat
Do tego możesz wymusić kontrolę typów, dzięki czemu zachowasz spójność obiektu.

  1. <?php 
  2. (object)$this->foo2 = $foo2; 
  3. ?>

o to chodzi?
Ludvik
Chodzi o:
  1. <?php
  2.  
  3. class Foo {
  4. private $db;
  5.  
  6. // Kontrola typów w konstruktorze
  7. public function __construct(DB $db) {
  8. $this->db = $db;
  9. }
  10.  
  11. public function a() {
  12. // Jeżeli DB implementuje metodę query(string)
  13. // to wiemy, że możemy ją zawsze tu wywołać.
  14. $this->db->query('zapytanie');
  15. }
  16. }
  17.  
  18. $db = new DB();
  19. $foo = new Foo($db);
  20.  
  21. ?>
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.