Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: PHP5 i Singletony
Forum PHP.pl > Forum > PHP > Object-oriented programming
Ozzy
Może mnie ktoś oświecić dlaczego używa się singletonów? np:

  1. <?php
  2. class Foo {
  3.  
  4.  
  5. private static $reference;
  6. private $test;
  7.  
  8.  
  9. private function __construct() {}
  10.  
  11.  
  12. public function bar() {
  13.  
  14. $this->test = 'test';
  15. $this->bar2();
  16.  
  17. }
  18.  
  19.  
  20. private function bar2() {}
  21.  
  22.  
  23. public static function getRef() {
  24.  
  25. if(self::$reference == null) {
  26. self::$reference = new Foo();
  27. }
  28.  
  29. return self::$reference;
  30.  
  31. }
  32.  
  33.  
  34. }
  35.  
  36. Foo::getRef()->bar();
  37. ?>


skoro to samo można osiągnąć w ten sposób?:

  1. <?php
  2. class Foo {
  3.  
  4.  
  5. private static $test;
  6.  
  7.  
  8. public static function bar() {
  9.  
  10. self::$test = 'test';
  11. self::bar2();
  12.  
  13. }
  14.  
  15. private static function bar2() {}
  16.  
  17.  
  18. }
  19.  
  20. Foo::bar();
  21. ?>


Widze jakie są różnice, jednak nie rozumiem dlaczego singletony są stosowane skoro zapis Foo::bar(); jest wygodniejszy i kod klasy krótszy...
Czy za pomocą singletonów można zrobić coś, o czym nie wiem?
Cudi
Sigleton pozwala Ci działać na jednej instancji danej klasy, i w pewien sposob uniezależnia Cię od zmiennych globalych. Z każdego miejsca w kodzie możesz pobrać instancję klasy przez klasa::GetInstance(), i masz pewność (o ile dobrze skonstruujesz metode GetInstance) że zawsze otrzymasz referencję do tego samego obiektu. Takie jest głowne załorzenie signletonu smile.gif
Ozzy
tak, ale w php5 nie musze używać zmiennych globalnych:) więc czy dalej jest sens używania singletonów?
Cudi
Singletony są zastępstwem dla obiektów globalnych (tak sie przyjeło w php 4 ), i zapewniam Cie że pojęcie to nie wzieło się z php, i w każdym obiektowym jezyku programowania ono występuje. Zapewniam również że znajdzie sie kiedyś sytuacja w której użycie singletonu będzie konieczne (lub bardziej praktyczne), więc to że używasz php 5 nie jest żadnym argumentem przeciw singletonom smile.gif Oczywiście jeśli można przekazać instancję w inny sposób (np. jako referencja w parametrze jakiejś metody) to warto skorzystać z tego rozwiązania, a nie pchać się wszędzie z singletonami winksmiley.jpg Wszystko zależy od tego jak zbudujesz swoją aplikację, jeśli będziesz potrzebował w którymś miejscu singletonu (np. dwie zupełnie nie powiązane ze sobą klasy, ale jednej nagle sie zachce skorzystać z danych drugiej, ale ciężko będzie utworzyć powiązanie by je sobie przekazać) użyjesz go, jeśli nie to nie musisz sobie zawracać tym głowy winksmiley.jpg
Ozzy
Ja cię rozumiem, ale w php5 nie ma takiej potrzeby, np Foo::bar(); dostępne jest z każdego miejsca w dokumencie(i będzie to zawsze ten sam obiekt), a te dwie klasy które sa w przykładzie mają to samo działanie(czyli singleton nie jest potrzebny?).
cichy
Cytat
Ja cię rozumiem, ale w php5 nie ma takiej potrzeby, np Foo::bar(); dostępne jest z każdego miejsca w dokumencie(i będzie to zawsze ten sam obiekt), a te dwie klasy które sa w przykładzie mają to samo działanie(czyli singleton nie jest potrzebny?).

Ale Foo::bar to jest dospet do konkretnej funkcji bez inicjowania klasy w ktorej sie znajduje.
A co jesli zainicjowałeś jakaś klase i w tej klasie znajduja sie zmienne ktore sa Ci potrzebne ? Tu własnie przydaje sie singleton, bo nie dość że masz dostęp do wszystkich funkcji to jeszcze masz dostep do wartosci zmiennych w tej klasie.

Pozdro
Ozzy
Cytat
w tej klasie znajduja sie zmienne ktore sa Ci potrzebne


No właśnie nie ma z tym problemu:) przypatrz się dokładnie, metody statyczne mają dostęp do pól statycznych (które mogą być nawet prywatne), więc ten sposób w niczym nie ustępuje singletonom.
Wankster
Simpson: Ozzy mówił o PHP5, a tam możesz się odwoływać do zmiennych klasowych poprzez Foo::$bar :wink:
cichy
a no to chyba ze tak. Nie znam aż tak dokłądnie php5 tongue.gif

Pozdro
Cudi
Tak czy siak singleton może być przydatny, nie będziemy przecież robili wszystkich właściwości i metod w klasie na static. Czasem lepiej będzie zrobić jedną statyczną zmienną z referencją do $this i pobrać ją przez odpowiednią metodę używając operatora ::. Czasami takie rozwiązanie będzie poprostu wygodniejsze, efektywniejsze i bezpieczniejsze winksmiley.jpg
Ozzy
Cytat
Tak czy siak singleton może być przydatny

przykład proszę:)
Cudi
Potrzebna by była bardzo rozbudowana klasa, a Ty musiałbyś mieć dostęp do wielu jej właściwości z prawie każdej metody. Wtedy ustawianie wszystkiego na static troche miajałoby się z celem. Weźmy naprzykład parser szablonów. W całym kodzie chcesz używać tylko jednej isntancji (wiadomo, assign), ale ciężko dostarczyć referencje do niej każdemu innemu obiektowi. Ustawianie wszystkich zmiennych klasowych w parserze szablonów byłoby karkolomne, natomiast w każdym obiekcie który będzie go potrzebował możesz pobrać instancję przez wywołanie odpowiedniej metody poprzez oparator statyczny. Jeśli chodzi o przykłady kodu, to ciężko mi jest coś teraz napisać, ale myśle że pod tym adresem znajdziesz dość ciekawy przykład wraz z opisem (niestety wszystko to odnośnie php 4, jednak niektóre rzeczy sie nie zmieniałją, metody/zmienne statyczne nie zastąpią Ci wszystkiego winksmiley.jpg)/
Ozzy
z tym się zgodzę, bo sam używam takiego rozwiązania, jednak dalej nie daje mi to spokoju.

cytat z http://www.phppatterns.com/index.php/artic...icleview/6/1/1/
Cytat
But first we have to overcome a small problem in php - the lack of static class variables (something that's coming in the Zend 2 engine)

[php:1:9bafc4226a]<?php
// A generic function to create and fetch static objects
function staticInstance($class) {
// Declare a static variable to hold the object instance
static $instance;

// If the instance is not there, create one
if(!isset($instance)) {
$instance =& new $class;
}
return($instance);
}

?>[/php:1:9bafc4226a]

Co jeśli klasa wygląda np tak:

[php:1:9bafc4226a]<?php

final class Temp {


private static $content;


public static function add($content) {

self::$content.= $content;

}


public static function get() {

return self::$content;

}


public static function clear() {

self::$content = '';

}


}

?>[/php:1:9bafc4226a]
Czy to też trzeba używać singletonu?
Nie lepiej jest właśnie tak?
Podobnie może wyglądać klasa do ubsługi bazy danych.

Na przykład:
[php:1:9bafc4226a]<?php

class SQL {


private static $conn;
private static $result = array();


public static function connect($host, $user, $pass, $db) {

self::$conn = @mysql_connect($host, $user, $pass);

if (!self::$conn || !@mysql_select_db($db, self::$conn)) {
trigger_error(mysql_error(), E_ERROR);
}

}


public static function query($query, $label = 'default') {

$result = @mysql_query($query, self::$conn);

if(!$result) {
trigger_error(mysql_error(), E_ERROR);
} else {
self::$result[$label] = $result;
}

}

itd...

?>[/php:1:9bafc4226a]

Nie lepiej używać:
[php:1:9bafc4226a]<?php
SQL::query('SELECT name FROM ...');

while($row = SQL::fetchArray()) {
print $row['name'];
}
?>[/php:1:9bafc4226a]

niż np:
[php:1:9bafc4226a]<?php
$sql = SQL::getRef();

$sql->query('SELECT name FROM ...');

while($row = $sql->fetchArray()) {
print $row['name'];
}
?>[/php:1:9bafc4226a]

:?:
Bora
z static nie można przesadzać bo przez nadmierne używanie mmogą sie pojawić dziwne błedy.
Mnie zastanbawia natomiast coś innego.


[php:1:419528b488]<?php
// A generic function to create and fetch static objects
function staticInstance($class) {
// Declare a static variable to hold the object instance
static $instance;

// If the instance is not there, create one
if(!isset($instance)) {
$instance =& new $class;
}
return($instance);
}
?>[/php:1:419528b488]
No i to działa pięknie ale co zrobić z klasami z parametrem questionmark.gif

[php:1:419528b488]<?php
$db = &staticInstance(DB);

class DB
{
public function __construct($server, $user, $password, $database, $debug)
{
........
}
}
?>[/php:1:419528b488]
Ozzy
Cytat
z static nie można przesadzać bo przez nadmierne używanie mmogą sie pojawić dziwne błedy.


Jakie?

Bora: To jest przykład dla PHP4, w PHP5 nie trzeba tak robić.
Cudi
Ja preferuję tworzenie wewnątrz klasy metodę która zwróci jej instancję. Dzięki temu moge przesłać parametry, ale jeśli instancja już istnieje to będą one zignorowane. Normalnie mają wartość ustawioną na null. Można też zrobić funkcję która będzie tworzyła hash wartości parametrów i wrzucała do tablicy statycznej z kluczem o wartości hasha i wartością elementu jako referencję do potrzebnej instancji. Dzieki temu będziemy mogli utowrzyć kilka globalnych instancji z różnymi parametrami (choć nie wiem czy podawanie parametrów przy każdym wywołaniu funkcji byłoby rzeczą przyjemną winksmiley.jpg).
Wracając do tematu signleton vs. static, uważam że nie powinno się nadużywać statica, nie potrafie tego niestety uzasadnić (może przyjdzie ktoś mądrzejszy i wytłumaczy), ale mam dziwne wrażenie że jednak coś jest nie tak z tymi staticami, że ich nadurzycie może powodować spadek efektywności lub błędy, bo inaczej wszyscy by się na to rzucili, a jakoś tak się nie stało winksmiley.jpg (AFAIR). Zresztą nie widze żadnej zalety w korzystaniu z :: a -> jeśli chodzi o wygode, prawda, musze zadbać o ściągnięcie instancji w odpowiedni obszar zmiennych, ale jeśli pozwoli mi to zaoszczędzić troche czasu lub zbędnych kłopotów to wole jednak takie rozwiązanie. Musze przyznać że problem mnie zaintrygował, i teraz już sam jestem ciekaw jak to jest z tymi signletonami. Szkoda że nie mam większego doświadczenia z innymi językami obiektowymi, bo tak to cięzko mi cokolwiek powiedzieć aby nie być gołosłownym, same domysły winksmiley.jpg
Bora
Cytat
Cytat
z static nie można przesadzać bo przez nadmierne używanie mmogą sie pojawić dziwne błedy.


Jakie?

Bora: To jest przykład dla PHP4, w PHP5 nie trzeba tak robić.


hmm czyli w php5 nie trzeba korzystać z singleton bo można odwoiłąć sie przez class::var questionmark.gif

A co do korzystania z static może zbierać śmieci które spowodują błędne działanie. Np będziesz miał błąd np w twoim przypadku z sql static quote nie zostanie ustawione na nową. quote sie wykona bp bedzie mialo poprawną starą werjse. Przy takim bugu może być potem problem z znalezieniem.
Ozzy
Bora: Foo::$bar do zmiennej i Foo::bar do stałej

Cudi: Mi też się wydaje, że powinno się używać singletonów, tylko zastanawiam się dlaczego:) W PHP4 było to uzasadnione, w PHP5 też musi się znaleźć jakiś powód;)

Naturalnie czasem bez singletonów się nie obejdzie. Weźmy na przykład klasę Template, gdy chcemy mieć jeden główny szablon, do którego moglibyśmy odwołać się z każdej innej klasy, wtedy możemy napisać np:

[php:1:71a7711270]<?php

final class Page {


private static $reference;


private function __construct() {}


public static function getRef() {

if(self::$reference == null) {
self::$reference = new Template('Main');
}

return self::$reference;

}


}

$main = Page::getRef();
$main->assign('title', 'Main');
$main->assign('css', 'file', 'main');

itd...

?>[/php:1:71a7711270]

Ale co w przypadkach małych klas, np takich jak Temp, pokazana wcześniej.
Nie ma sensu chyba tworzyć zmiennej referencji gdy zależy nam na wygodnym i szybkim dostępie do metod, np Temp::clear(), Temp::add('test'); Temp::get() itd...

To samo tyczy się klasy SQL, nie zaobserwowałem gromadzenia się żadnych śmieci, nie wygląda też, żeby działała wolniej.

Chyba faktycznie musimy poczekać na kogoś mądrzejszego:)
Cudi
Myśle że właśnie sam sobie odpowiedziałeś na swoje pytanie smile.gif Przy większych klasach singleton może być przydatny, ale w klasie np. Config, któtra ma za zadanie jedynie przechowywać dla nas jakieś informacje dużo wygodniejszym wyjściem będzie odowołanie się przez operator statyczny. Nie musimy się wtedy martwić o instancje, co byloby problemem jesli chcielibyśmy pobrać w jakiejś metodzie dane tylko w jednym miejscu. Zresztą ja próbowałem robić takie numery już w php 4, było to troche karkołomne ale działało. Otóż każda metoda klasy Klasa przy pierwszym wywołaniu wywoływala Klasa::GetInstance() i zapisywała referencje do zmiennej statycznej. Dane były umieszczone w zmiennych klasowych, ale ja miałem ten konfort że mogłem je pobierać przez Klasa::Get(), a sama metoda troszczyła sie o pobranie instancji odpowiedniego obiektu smile.gif Oczywiście w php 5 jest to już zbędne, klasowe zmienne statyczne załatwiają sprawe smile.gif
Balin
czy moglibyscie podac linki do artykulow omawiajacych szczegolowo temat singletonow ?
[sorry za maly ot]
Ozzy
http://www.phppatterns.com/index.php/artic...ticleview/6/1/1
http://www.phppatterns.com/index.php/artic...cleview/75/1/1/
http://www.sitepoint.com/article/1192/9 - PHP5

i jeszcze php Solutions najnowszy (artykuł o singletonach jest na końcu)
hawk
Formalnie rzecz biorąc, singletony nie są potrzebne i da się zrobić to samo na zmiennych "klasowych", czyli tak naprawdę na zmiennych globalnych (jedyna różnica, że zamiast $bar piszemy Foo::$bar). Ale zmienne globalne, jak wiadomo, są brzydkie i bebe, i dlatego w OOP stosuje się singletony.

Zresztą, singletony mogą teoretycznie trochę więcej. Można - choć jest to trudne - zrobić singleton który można inicjować parametrem, używając wyjątków i new (ale to w Javie widziałem sad.gif ). Można również - choć to również trudne, z uwagi na pokręcony proces inicjacji obiektu - próbować dziedziczenia.

Można wreszcie - i to jest chyba najważniejsze - przekazywać sobie referencje do obiektu singletonowego. Jeżeli mamy singleton Foo implementujący interfejs Bar, to możemy sobie przekazywać referencję do Foo (uzyskaną przez Foo::getInstance() ) i nie zastanawiać się co to jest - implementuje Bar i to wystarcza.

Czyli singleton jest odpowiednikiem kodu globalnego w OOP, i kilka rzeczy specyficznych dla OOP potrafi "dodatkowo" zrobić.

A poza tym, wielkie klasy z samymi metodami statycznymi są oznaką amatorstwa, a mały singleton tu i ówdzie wygląda profesjonalnie smile.gif .
Ozzy
Cytat
A poza tym, wielkie klasy z samymi metodami statycznymi są oznaką amatorstwa, a mały singleton tu i ówdzie wygląda profesjonalnie .


Tak też myslałem:)
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.