Co robi new self (); znaczy w PHP?

110

Nigdy nie widziałem takiego kodu:

public static function getInstance()
{
    if ( ! isset(self::$_instance)) {
        self::$_instance = new self();
    }
    return self::$_instance;
}

Czy to jest to samo co new className()?

EDYTOWAĆ

Jeśli klasa jest dziedziczona, na którą klasę wskazuje?

user198729
źródło
@ stereofrog, czy masz na myśli porzucenie wzorca singleton? Ale wszystko istnieje z jakiegoś powodu, prawda?
user198729
Aha, zgadzam się z tym punktem: singleton powinien zostać wymieniony na fabryczny
user198729
@stereofrog Singleton są trucizną dla testów jednostkowych, niezwykle trudno jest wykonać niezmienne testy czegoś, co zmienia stan z jednego wywołania do drugiego.
David
Niestety ta metoda się nie rozszerzy. Zawsze da ci nowy obiekt z klasy, w której ta funkcja została zdefiniowana.
Ares

Odpowiedzi:

211

self wskazuje na klasę, w której jest napisany.

Tak więc, jeśli metoda getInstance znajduje się w nazwie klasy MyClass, następujący wiersz:

self::$_instance = new self();

Zrobi to samo, co:

self::$_instance = new MyClass();



Edycja: jeszcze kilka informacji, po komentarzach.

Jeśli masz dwie klasy, które się wzajemnie rozszerzają, masz dwie sytuacje:

  • getInstance jest zdefiniowany w klasie podrzędnej
  • getInstance jest zdefiniowany w klasie nadrzędnej

Pierwsza sytuacja wyglądałaby tak (usunąłem cały niepotrzebny kod, dla tego przykładu - będziesz musiał dodać go z powrotem, aby uzyskać zachowanie singletona) *:

class MyParentClass {

}
class MyChildClass extends MyParentClass {
    public static function getInstance() {
        return new self();
    }
}

$a = MyChildClass::getInstance();
var_dump($a);

Tutaj otrzymasz:

object(MyChildClass)#1 (0) { } 

Co selfoznaczaMyChildClass - czyli klasy, w którym jest napisane.


W drugiej sytuacji kod wyglądałby następująco:

class MyParentClass {
    public static function getInstance() {
        return new self();
    }
}
class MyChildClass extends MyParentClass {

}

$a = MyChildClass::getInstance();
var_dump($a);

Otrzymasz taki wynik:

object(MyParentClass)#1 (0) { }

Co oznacza, że selfśrodki MyParentClass- czyli tu też klasa, w którym jest napisane .




W PHP <5.3, „klasa, w której jest napisane” jest ważna - i może czasami powodować problemy.

Dlatego PHP 5.3 wprowadza nowe użycie staticsłowa kluczowego: może być teraz używane dokładnie tam, gdzie użyliśmy selfw tych przykładach:

class MyParentClass {
    public static function getInstance() {
        return new static();
    }
}
class MyChildClass extends MyParentClass {

}

$a = MyChildClass::getInstance();
var_dump($a);

Ale staticzamiast tego selfotrzymasz:

object(MyChildClass)#1 (0) { } 

Co oznacza, że ​​ten staticrodzaj wskazuje na używaną (przez nas MyChildClass::getInstance()) klasę , a nie tę, w której jest napisane.

Oczywiście zachowanie selfnie zostało zmienione, aby nie zepsuć istniejących aplikacji - PHP 5.3 właśnie dodało nowe zachowanie, przetwarzając staticsłowo kluczowe.


A mówiąc o PHP 5.3, możesz rzucić okiem na stronę Późne statyczne powiązania w podręczniku PHP.

Pascal MARTIN
źródło
@Paul: heu ... oznaczało „self działa jako alias do” lub „self w pewnym sensie wskazuje na” - można w tym celu użyć czasownika „designer” w języku francuskim - przypuszczam, że to jedna z sytuacji w którym używanie tego samego słowa po angielsku nie jest dobrym pomysłem ;-( edytuję swoją odpowiedź, aby to naprawić ;; dzięki :-)
Pascal MARTIN
Co zrobić, jeśli istnieje baseclass, class, który z nich to wskazywać?
user198729
@ użytkownik: zredagowałem swoją odpowiedź, aby podać więcej informacji na temat selfdziedziczenia; a także zamieściłem kilka informacji o staticPHP 5.3 ;; mam nadzieję, że to pomoże :-)
Pascal MARTIN
10

Wydaje się, że jest to implementacja wzorca Singleton . Funkcja jest wywoływana statycznie i sprawdza, czy klasa statyczna zawiera zmienną$_instance ustawioną .

Jeśli tak nie jest, inicjalizuje swoje wystąpienie ( new self()) i przechowuje je w$_instance .

Jeśli zadzwonisz className::getInstance(), otrzymasz jedno i to samo instancję klasy w każdym wywołaniu, co jest punktem wzorca singleton.

Jednak nigdy nie widziałem tego w ten sposób i szczerze mówiąc nie wiedziałem, że to możliwe. Co jest $_instancezadeklarowane jako w klasie?

Pekka
źródło
1
$_instancejest zadeklarowany jakopublic static $_instance;
Atif
7

Jest to najprawdopodobniej używane w pojedynczym wzorcu projektowym, w którym konstruktor jest zdefiniowany jako prywatny, aby uniknąć tworzenia instancji, (::)operator podwójnego dwukropka może uzyskać dostęp do elementów członkowskich, które są zadeklarowane jako statyczne wewnątrz klasy, więc jeśli istnieją statyczne elementy członkowskie, pseudozmienna $ nie można tego użyć, dlatego zamiast tego kod używał self, Singletons to dobre praktyki programistyczne, które pozwalają tylko na 1 wystąpienie obiektu, takiego jak programy obsługi konektora bazy danych. Z kodu klienta dostęp do tej instancji odbywałby się poprzez utworzenie pojedynczego punktu dostępu, w tym przypadku nazwał gogetInstance() odbywałby się , Funkcja getInstance sama w sobie była funkcją, która utworzyła obiekt w zasadzie przy użyciu słowa kluczowego new do utworzenia obiektu, co oznacza, że ​​metoda konstruktora została nazywane również.

linia if(!isset(self::instance))sprawdza, czy obiekt został już utworzony, nie możesz tego zrozumieć, ponieważ kod jest tylko fragmentem, gdzieś na górze powinny być statyczne elementy, jak prawdopodobnie

private static $_instance = NULL; 

w normalnych klasach uzyskalibyśmy dostęp do tego członka po prostu

$this->_instance = 'something';

ale jest zadeklarowany jako statyczny, więc nie mogliśmy użyć zamiast tego kodu $ this

self::$_instance

sprawdzając, czy w tej statycznej zmiennej klasy znajduje się obiekt, klasa może następnie zdecydować o utworzeniu lub nie utworzeniu pojedynczej instancji, więc jeśli nie jest ona ustawiona,! isset, co oznacza, że ​​żaden obiekt nie istnieje w statycznym elemencie $ _instance, a następnie generuje nowy obiekt, zapisuje go w elemencie statycznym $_instanceza pomocą polecenia

self::$_instance = new self();

i zwrócił go do kodu klienta. Kod klienta może wtedy szczęśliwie używać pojedynczej instancji obiektu z jego metodami publicznymi, ale w kodzie klienta, wywołując pojedynczy punkt dostępu, to znaczy getInstance()metoda jest również trudna, musi być wywołana w ten sposób

$thisObject = className::getInstance();

z tego powodu funkcja sama w sobie jest deklarowana jako statyczna.

flimh
źródło
2

Tak, to jak new className()(odnosząc się do klasy zawierającej tę metodę), prawdopodobnie używane we wzorcu Singleton, w którym konstruktor jest prywatny.

Matteo Riva
źródło
Dlaczego ktoś miałby używać wzorca Singleton w PHP? O ile nie zostanie użyty w programie podobnym do demona, singleton będzie istniał tylko podczas działania skryptu, a następnie zniknie wraz z programem.
ILikeTacos,
4
aby uniknąć irytującego deklarowania globalnego dostępu do zmiennej globalnej
Sam Adamsh
0

Jeśli klasa jest dziedziczona, wywołanie metody getInstance () od child nie da ci instancji child. Zwróci tylko instancję instancji nadrzędnej. Dzieje się tak, ponieważ nazywamy new self ().

Jeśli chcesz, aby klasa potomna zwróciła instancję klasy potomnej, użyj funkcji new static () w funkcji getInstance (), a następnie zwróci instancję klasy potomnej. Nazywa się to późnym wiązaniem !!

kta
źródło