Jaka jest korzyść z używania singletona zamiast globalnego do połączeń z bazą danych w PHP? Czuję, że używanie singletona zamiast globalnego sprawia, że kod jest niepotrzebnie skomplikowany.
Kod z Global
$conn = new PDO(...);
function getSomething()
{
global $conn;
.
.
.
}
Kodowanie za pomocą Singletona
class DB_Instance
{
private static $db;
public static function getDBO()
{
if (!self::$db)
self::$db = new PDO(...);
return self::$db;
}
}
function getSomething()
{
$conn = DB_Instance::getDBO();
.
.
.
}
Jeśli istnieje lepszy sposób na zainicjowanie połączenia z bazą danych inny niż globalny lub pojedynczy, wspomnij o tym i opisz zalety, jakie ma w porównaniu z globalnym lub pojedynczym.
php
design-patterns
singleton
Imran
źródło
źródło
Odpowiedzi:
Wiem, że to stare, ale odpowiedź Dr8k była prawie gotowa .
Kiedy rozważasz napisanie fragmentu kodu, załóż, że to się zmieni. Nie oznacza to, że zakładasz rodzaje zmian, które w pewnym momencie przyniesie to w przyszłości, ale raczej, że nastąpi jakaś zmiana.
Niech to będzie cel, złagodzenie bólu związanego z wprowadzaniem zmian w przyszłości: globalny jest niebezpieczny, ponieważ trudno nim zarządzać w jednym miejscu. Co się stanie, jeśli w przyszłości chcę uwrażliwić kontekst połączenia z bazą danych? Co jeśli chcę, aby zamykał się i otwierał ponownie co piąty raz, gdy był używany. Co się stanie, jeśli zdecyduję, że w celu skalowania mojej aplikacji chcę użyć puli 10 połączeń? A może konfigurowalna liczba połączeń?
Fabryka Singleton daje taką elastyczność. Skonfigurowałem to z bardzo małą dodatkową złożonością i zyskuję więcej niż tylko dostęp do tego samego połączenia; Uzyskuję możliwość zmiany sposobu, w jaki to połączenie jest później do mnie przekazywane w prosty sposób.
Zauważ, że mówię o pojedynczej fabryce, a nie po prostu o singletonie . To prawda, że istnieje niewielka różnica między singletonem a globalnym. Z tego powodu nie ma powodu, aby mieć pojedyncze połączenie: dlaczego miałbyś spędzać czas na konfigurowaniu tego, skoro zamiast tego możesz utworzyć zwykły globalny?
To, co daje ci fabryka, to powód, dla którego chcesz uzyskać połączenia, i oddzielne miejsce, w którym możesz zdecydować, jakie połączenia (lub połączenie) otrzymasz.
Przykład
class ConnectionFactory { private static $factory; private $db; public static function getFactory() { if (!self::$factory) self::$factory = new ConnectionFactory(...); return self::$factory; } public function getConnection() { if (!$this->db) $this->db = new PDO(...); return $this->db; } } function getSomething() { $conn = ConnectionFactory::getFactory()->getConnection(); . . . }
Następnie, w ciągu 6 miesięcy, gdy Twoja aplikacja jest bardzo znana, zostaje dugg and slashdotted, a Ty zdecydujesz, że potrzebujesz więcej niż jednego połączenia, wszystko, co musisz zrobić, to zaimplementować kilka pul w metodzie getConnection (). Lub jeśli zdecydujesz, że potrzebujesz opakowania, które implementuje rejestrowanie SQL, możesz przekazać podklasę PDO. Lub jeśli zdecydujesz, że chcesz mieć nowe połączenie przy każdym wywołaniu, możesz to zrobić. Jest elastyczny zamiast sztywnego.
16 linii kodu, w tym nawiasy klamrowe, co pozwoli Ci zaoszczędzić wiele godzin na refaktoryzacji do czegoś niesamowicie podobnego w przyszłości.
Zauważ, że nie uważam tego „Pełzania funkcji”, ponieważ nie wykonuję żadnej implementacji funkcji w pierwszej turze. To pogranicze „Future Creep”, ale w pewnym momencie pomysł, że „kodowanie na jutro dzisiaj” jest zawsze złą rzeczą, nie podoba mi się.
źródło
return self::$factory->getConnection();
zamiastreturn self::$factory;
?Nie jestem pewien, czy potrafię odpowiedzieć na twoje konkretne pytanie, ale chciałem zasugerować, że obiekty połączeń globalnych / pojedynczych mogą nie być najlepszym pomysłem, jeśli tak jest w przypadku systemu internetowego. Systemy DBMS są generalnie zaprojektowane do zarządzania dużą liczbą unikalnych połączeń w efektywny sposób. Jeśli używasz globalnego obiektu połączenia, robisz kilka rzeczy:
Zmuszanie stron do wykonywania wszystkich połączeń z bazą danych po kolei i zabijanie wszelkich prób asynchronicznego ładowania stron.
Potencjalne utrzymywanie otwartych blokad na elementach bazy danych dłużej niż to konieczne, spowalniając ogólną wydajność bazy danych.
Maksymalizacja łącznej liczby jednoczesnych połączeń, które Twoja baza danych może obsługiwać, i blokowanie dostępu do zasobów nowym użytkownikom.
Jestem pewien, że są też inne potencjalne konsekwencje. Pamiętaj, że ta metoda będzie próbować utrzymać połączenie z bazą danych dla każdego użytkownika uzyskującego dostęp do serwisu. Jeśli masz tylko jednego lub dwóch użytkowników, nie ma problemu. Jeśli jest to publiczna witryna internetowa i chcesz mieć ruch, skalowalność stanie się problemem.
[EDYTOWAĆ]
W sytuacjach o większej skali tworzenie nowych połączeń za każdym razem, gdy trafisz na bazę danych, może być złe. Jednak odpowiedzią nie jest tworzenie połączenia globalnego i ponowne wykorzystywanie go do wszystkiego. Odpowiedzią jest pule połączeń.
Dzięki buforowaniu połączeń obsługiwanych jest wiele różnych połączeń. Gdy aplikacja wymaga połączenia, pierwsze dostępne połączenie z puli jest pobierane, a następnie zwracane do puli po wykonaniu zadania. Jeśli zażądano połączenia i żadne nie jest dostępne, nastąpi jedna z dwóch rzeczy: a) jeśli maksymalna liczba dozwolonych połączeń nie zostanie osiągnięta, zostanie otwarte nowe połączenie lub b) aplikacja będzie zmuszona czekać, aż połączenie stanie się dostępne .
Uwaga: W językach .Net pule połączeń są domyślnie obsługiwane przez obiekty ADO.Net (parametry połączenia ustawiają wszystkie wymagane informacje).
Dzięki Crad za skomentowanie tego.
źródło
Metoda singleton została utworzona, aby upewnić się, że istnieje tylko jedno wystąpienie dowolnej klasy. Ale ponieważ ludzie używają go jako sposobu na skrócenie globalizacji, staje się znane jako leniwe i / lub złe programowanie.
Dlatego zignorowałbym global i Singleton, ponieważ oba nie są tak naprawdę OOP.
To, czego szukałeś, to zastrzyk zależności .
Możesz sprawdzić łatwe do odczytania informacje oparte na PHP związane z wstrzykiwaniem zależności (z przykładami) na http://components.symfony-project.org/dependency-injection/trunk/book/01-Dependency-Injection
źródło
Oba wzorce osiągają ten sam efekt netto, zapewniając jeden punkt dostępu do wywołań bazy danych.
Jeśli chodzi o konkretną implementację, singleton ma niewielką zaletę polegającą na tym, że nie inicjuje połączenia z bazą danych, dopóki co najmniej jedna z innych metod nie zażąda tego. W praktyce w większości napisanych przeze mnie aplikacji nie robi to dużej różnicy, ale jest to potencjalna zaleta, jeśli masz strony / ścieżki wykonywania, które w ogóle nie wykonują żadnych wywołań bazy danych, ponieważ te strony nie kiedykolwiek zażądać połączenia z bazą danych.
Jeszcze jedna drobna różnica polega na tym, że globalna implementacja może nieumyślnie podeptać inne nazwy zmiennych w aplikacji. Jest mało prawdopodobne, że kiedykolwiek przypadkowo zadeklarujesz inne globalne odniesienie $ db, chociaż możliwe jest, że możesz je przypadkowo nadpisać (powiedzmy, piszesz if ($ db = null), gdy zamierzałeś napisać if ($ db == null). Pojedynczy obiekt zapobiega temu.
źródło
Jeśli nie zamierzasz używać trwałego połączenia, a są przypadki, w których tego nie robisz, uważam, że singleton jest koncepcyjnie bardziej akceptowalny niż globalny w projektowaniu obiektów obiektowych.
W prawdziwej architekturze OO singleton jest bardziej efektywny niż tworzenie nowej instancji obiektu za każdym razem.
źródło
W podanym przykładzie nie widzę powodu, aby używać singletonów. Z reguły, jeśli moim jedynym zmartwieniem jest zezwolenie na pojedyncze wystąpienie obiektu, jeśli pozwala na to język, wolę używać globali
źródło
Generalnie użyłbym singletona do połączenia z bazą danych ... Nie chcesz tworzyć nowego połączenia za każdym razem, gdy potrzebujesz interakcji z bazą danych ... Może to zaszkodzić wydajności i przepustowości twojej sieci ... Po co tworzyć nowy, jeśli jest dostępny ... Tylko moje 2 centy ...
RWendi
źródło
To całkiem proste. Nigdy nie używaj global OR Singleton.
źródło
Zgodnie z radą, zarówno singleton, jak i globalne są ważne i można je łączyć w ramach tego samego systemu, projektu, wtyczki, produktu itp ... W moim przypadku tworzę produkty cyfrowe dla sieci (wtyczki).
Używam tylko singletona w głównej klasie i używam go z zasady. Prawie go nie używam, ponieważ wiem, że klasa główna nie utworzy jej ponownie
<?php // file0.php final class Main_Class { private static $instance; private $time; private final function __construct() { $this->time = 0; } public final static function getInstance() : self { if (self::$instance instanceof self) { return self::$instance; } return self::$instance = new self(); } public final function __clone() { throw new LogicException("Cloning timer is prohibited"); } public final function __sleep() { throw new LogicException("Serializing timer is prohibited"); } public final function __wakeup() { throw new LogicException("UnSerializing timer is prohibited"); } }
Globalne zastosowanie dla prawie wszystkich klas drugorzędnych, na przykład:
<?php // file1.php global $YUZO; $YUZO = new YUZO; // YUZO is name class
podczas gdy w czasie wykonywania mogę użyć Global do wywołania ich metod i atrybutów w tej samej instancji, ponieważ nie potrzebuję innej instancji mojej głównej klasy produktu.
<?php // file2.php global $YUZO; $YUZO->method1()->run(); $YUZO->method2( 'parameter' )->html()->print();
Dostaję z globalnym to użycie tej samej instancji, aby produkt działał, ponieważ nie potrzebuję fabryki dla instancji tej samej klasy, zwykle fabryka instancji jest przeznaczona dla dużych systemów lub do bardzo rzadkich celów.
In conclusion:
, musisz, jeśli już dobrze rozumiesz, że jest to Singleton anty-wzorzec i rozumiesz Global , możesz użyć jednej z 2 opcji lub je mieszać, ale jeśli nie zalecam nadużywania, ponieważ jest wielu programistów, którzy są bardzo wyjątkowi i wierni programowania OOP, używaj go do klas głównych i drugorzędnych, których często używasz w czasie wykonywania. (Oszczędza dużo procesora). 😉źródło