[PHP] Singelton

[PHP] Singelton
0

W Internecie pełno jest przykładów w których to pisze by obsługę bazy danych robić w singeltonie powiedzmy pliki db.php. Mam tylko jedno pytanie. Po co? Za każdym razem gdy includuje ten plik db.php (albo require itd - ja używam require_once) niejako dołączona zostaje nowa instancja singeltona... Sprawdzałem to bo zrobiłem echo przy pobieraniu instancji obiektu gdy ten musi zostać stworzony, bo nie jest. I to "echo" widzę za każdym razem. Czyli to i tak powiela się w pamięci! Nie wiem czy robię coś nie tak? Czy tak ma być? Kopiowałem przykłady z wielu źródłem i za każdym razem tworzona jest nowa instancja! Statyczne pole jest puste. W takim razie po co? Jak najlepiej zaimplementować obiektowo obsługę bazy danych?
Tworzyć nowy obiekt. Wykonywać połączenie, później zapytanie i usuwać obiekt w każdym odwołaniu do bazy? Tylko to rozwiązanie wydaje mi się rozsądne (by nie zaśmiecać pamięci). Czy się może mylę?

Załączam obecny kod singeltona (bez dodatkowych funkcji)

Kopiuj
class DataBase {

private static $oInstance = false;  

public static function getInstance()
{ 
     if (self::$oInstance == false) 
     { 
         echo "Tworze obiekt";//Sprawdzenie
         self::$oInstance = new DataBase(); 
     } 
    return self::$oInstance; 
}  
        
}
Koziołek
Moderator
  • Rejestracja:około 18 lat
  • Ostatnio:5 dni
  • Lokalizacja:Stacktrace
  • Postów:6822
0

Takie zachowanie wynika z samej specyfiki php. Nie ma tu tak jak w Javie czy Cpp możliwości trwałego umieszczenia obiektu w pamięci w ramach aplikacji. Interpreter języka po zakończeniu działania skryptu niszczy wszystkie obiekty.
Spróbuj z taką implementacją:

Kopiuj
class Obj{
	private $mysql;

	private function __construct(){
		$this->mysql = new mysqli();
	}
	function __destruct(){
			$this->mysql->close(); 
       }
    
        private static $INSTANCE;
 
     	public static function getInstance(){
	    	if(isset(self::$INSTANCE)){
	    		return self::$INSTANCE;
	    	}
	    	else{
	    		self::$INSTANCE = new Obj();
	    		return self::$INSTANCE;
	    	}
    	}
}

Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
prgtw
  • Rejestracja:około 23 lata
  • Ostatnio:około 5 lat
  • Postów:255
0

Nie rozumiesz idei singletonu w takim razie, więc przykład:

Kopiuj
class Obj{
  public function __construct(){
    print 'OBJ CREATED';
  };
}

$res1 = new Obj();
$res2 = new Obj();
$res2 = new Obj();

var_dump($res1);
var_dump($res2);
var_dump($res3);

# widac ze w obrebie skryptu bylu 3 instancje obiektu Obj

# teraz zakladamy ze Obj jest singletonem
$res1 = Obj::getInstance();
$res2 = Obj::getInstance();
$res3 = Obj::getInstance();

var_dump($res1);
var_dump($res2);
var_dump($res3);

# widac ze jest 1 kopia Obj w pamieci a kazda zmienna sie do niego odwoluje - widac to po numerkach np. #1 - to jest instancja obiektu
0

Rozumiem idee, tylko nie rozumiem sensu stosowania tego rozwiązania skoro nie jest tak jak w innych językach. Sztandarowym przykładem zastosowania ma niby być singelton z bazą danych. Ale to nie ma sensu i właśnie go nie widzę bo i tak w skrypcie utworzyłbym na początku nowy obiekt

Kopiuj
$db = new DataBase();

co jest właśnie zawsze w praktyce równoznacze z

Kopiuj
self::$oInstance = new DataBase(); 

bo po co miałbym tworzyć niby $db1, $db2 (zakładając, że komunikować miałbym się tylko z jedną bazą)? Ten przykład jest nieżyciowy. Ergo w praktycznym bazodanowym zastosowaniu i tak powstanie jeden obiekt, który zostanie "zniszczony" po zakończeniu skryptu. Gdyby nie był niszczony to takie rozwiązanie miałoby sens.

nav
  • Rejestracja:ponad 21 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:Warszawa
0

Przy wielu modułach, nie musisz przekazywać każdemu obiektu bazy danych. Po prostu ładujesz moduł a on sam sobie znajduje bazę przy pomocy singletona.


utf-8 rlz! ٩(ಥ_ಥ)۶
Koziołek
Moderator
  • Rejestracja:około 18 lat
  • Ostatnio:5 dni
  • Lokalizacja:Stacktrace
  • Postów:6822
0

@pawel42, a następnie twój skrypt weźmie do konserwacji jakiś inny miś i nieświadomy tego co się dzieje w skryptach utworzy dodatkowe połączenie? Lub też wykona przypadkowo taki manewr:

Kopiuj
$db = "debug";

Singletony w php w pewnym stopniu zabezpieczają nas przed problemami związanymi z dynamicznym typowaniem i programowaniem obiektowym. Zresztą singleton bazodanowy to nie tylko utrzymywanie porządku w połączeniach z DB, ale też i optymalizacja kodu oraz możliwość stworzenia jednego obiektu do zarządzania całą zabawą z bazą. Obsługa zapytań, zwracanie wyników, transakcje itp.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
prgtw
  • Rejestracja:około 23 lata
  • Ostatnio:około 5 lat
  • Postów:255
0

Dobrze powiedziałem że jednak nie rozumiesz idei singletonu. Załóżmy że masz jakiś skrypt który poszerzasz o moduły. Jeden z nich ładuje klasę bazodanową i zapisuje w zmiennej $DB dla siebie. Ty piszesz dodatkowy moduł i też chcesz korzystać z bazy danych.

Nie robisz wtedy

Kopiuj
global $DB;

i wykorzystujesz bazę na tej zmiennej tylko pobierasz instancję obiektu klasy bazodanowej i umieszczasz w swojej zmiennej, nie musisz wiedzieć pod jaką zmienną została zapisana baza chcąc z niej skorzystać.

Tak po polsku:
Załóżmy że masz 1000 wierszy w excelu i moduł do wyszukania konkretnej pozycji. Tworzysz instancję klasy tego modułu a on znajduje np. pozycję nr 500 i zapamiętuje ją ... w innym miejscu w skrypcie chcesz znaleźć to samo. Tworząc nową instancję znowu będziesz szukał - po co, singleton zobaczy że klasa już istnieje i że coś wyszukała i zwraca klasę ale już z ustawioną pozycją - no już nie wiem jak mogę to jeszcze prościej wytłumaczyć.

Język PHP to język interpretowany w real-time, więc nie da się zapisać między sesjami np. aktywnego połączenia z bazą danych, choć obietky itp. się da (przez serializację, która umożliwia pełne odtworzenie).

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.