Cosa fa new self (); intendi in PHP?


110

Non ho mai visto un codice come questo:

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

È lo stesso di new className()?

MODIFICARE

Se la classe è ereditaria, a quale classe punta?



@ stereofrog, intendi che il pattern singleton dovrebbe essere abbandonato? Ma tutte le cose esistono per una ragione, giusto?
user198729

Oh, tendo ad essere d'accordo con questo punto: singleton dovrebbe essere sostituito da factory
user198729

@stereofrog Singleton sono veleni per i test unitari, è estremamente difficile fare test immutabili su qualcosa che cambia stato da una chiamata all'altra.
David

Sfortunatamente, questo metodo non si estenderà. Ti darà sempre un nuovo oggetto dalla classe in cui è stata definita questa funzione.
Ares

Risposte:


211

self indica la classe in cui è scritto.

Quindi, se il tuo metodo getInstance è in un nome di classe MyClass, la riga seguente:

self::$_instance = new self();

Farà lo stesso di:

self::$_instance = new MyClass();



Modifica: un paio di informazioni in più, dopo i commenti.

Se hai due classi che si estendono a vicenda, hai due situazioni:

  • getInstance è definito nella classe figlio
  • getInstance è definito nella classe genitore

La prima situazione sarebbe simile a questa (ho rimosso tutto il codice non necessario, per questo esempio - dovrai aggiungerlo di nuovo per ottenere il comportamento singleton) *:

class MyParentClass {

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

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

Qui otterrai:

object(MyChildClass)#1 (0) { } 

Il che significa che selfi mezzi MyChildClass- cioè la classe in cui è scritto.


Per la seconda situazione, il codice sarebbe simile a questo:

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

}

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

E otterrai questo tipo di output:

object(MyParentClass)#1 (0) { }

Il che significa che selfi mezzi MyParentClass- cioè anche qui, la classe in cui è scritto .




Con PHP <5.3, "la classe in cui è scritto" è importante e talvolta può causare problemi.

Ecco perché PHP 5.3 introduce un nuovo utilizzo per la staticparola chiave: ora può essere utilizzata esattamente dove l'abbiamo usata selfin quegli esempi:

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

}

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

Ma, con staticinvece di self, ora otterrai:

object(MyChildClass)#1 (0) { } 

Il che significa che quel statictipo di punti punta alla classe che viene utilizzata (che abbiamo usato MyChildClass::getInstance()) e non a quella in cui è scritta.

Ovviamente, il comportamento di selfnon è stato modificato, per non rompere le applicazioni esistenti - PHP 5.3 ha appena aggiunto un nuovo comportamento, riciclando la staticparola chiave.


E, parlando di PHP 5.3, potresti dare un'occhiata alla pagina Late Static Bindings del manuale PHP.


@Paul: heu ... significava "self agisce come un alias di", o "self kind of points to" - il verbo "designer", in francese, può essere usato per questo - suppongo che sia una delle situazioni in cui usare la stessa parola in inglese non è una buona idea ;-( Modificherò la mia risposta per risolvere questo problema ;; grazie :-)
Pascal MARTIN

Che cosa succede se v'è baseclass, classche lo si fa puntare a?
user198729

@user: ho modificato la mia risposta per fornire un po 'più di informazioni selfsull'ereditarietà; e ho anche incluso alcune informazioni su staticin PHP 5.3 ;; spero che questo aiuti :-)
Pascal MARTIN

10

Questa sembra essere un'implementazione del pattern Singleton . La funzione viene chiamata staticamente e controlla se la classe statica ha la variabile $_instanceimpostata.

In caso contrario, inizializza un'istanza di se stesso ( new self()) e la memorizza in $_instance.

Se chiami className::getInstance()otterrai la stessa istanza di classe su ogni chiamata, che è il punto del pattern singleton.

Non l'ho mai visto in questo modo, però, e onestamente non sapevo che fosse possibile. Cosa viene $_instancedichiarato in classe?


1
$_instanceè dichiarato comepublic static $_instance;
Atif

7

Questo è molto probabilmente utilizzato nel pattern di progettazione singleton, in cui il costruttore è definito come privato in modo da evitare di essere istanziato, l' (::)operatore doppio due punti può accedere ai membri dichiarati statici all'interno della classe, quindi se ci sono membri statici, la pseudo variabile $ questo non può essere utilizzato, quindi il codice utilizzato è self, i singleton sono buone pratiche di programmazione che consentiranno solo 1 istanza di un oggetto come i gestori di connettori di database. Dal codice client, l'accesso a quell'istanza sarebbe stato fatto creando un singolo punto di accesso, in questo caso lo ha chiamato getInstance(), getInstance in sé era la funzione che ha creato l'oggetto fondamentalmente utilizzando la nuova parola chiave per creare un oggetto, il che significa che il metodo del costruttore era chiamato anche.

la riga if(!isset(self::instance))controlla se un oggetto è già stato creato, non potresti capirlo perché il codice è solo un frammento, da qualche parte in alto, dovrebbero esserci membri statici come probabilmente

private static $_instance = NULL; 

nelle classi normali avremmo avuto accesso a questo membro semplicemente

$this->_instance = 'something';

ma è dichiarato statico e quindi non possiamo usare il codice $ this che usiamo invece

self::$_instance

controllando se c'è un oggetto memorizzato su questa variabile di classe statica, la classe può quindi decidere di creare o meno una singola istanza, quindi se non è impostato,! isset, che significa che non esiste alcun oggetto sul membro statico $ _istanza, allora genera un nuovo oggetto, memorizzato nel membro statico $_instancedal comando

self::$_instance = new self();

e lo ha restituito al codice client. Il codice client può quindi usare felicemente la singola istanza dell'oggetto con i suoi metodi pubblici, ma nel codice client, chiamando il singolo punto di accesso, cioè, anche il getInstance()metodo è complicato, deve essere chiamato in questo modo

$thisObject = className::getInstance();

il motivo, la funzione in sé è dichiarata statica.


2

Sì, è come new className()(riferito alla classe contenente quel metodo), probabilmente usato in un pattern Singleton in cui il costruttore è privato.


Perché qualcuno dovrebbe usare il pattern Singleton in PHP? A meno che non venga utilizzato in un programma simile a un demone, il singleton vivrà solo durante l'esecuzione dello script e quindi scomparirà insieme al programma.
ILikeTacos

4
per evitare di dichiarare irritantemente globale per accedere a una variabile globale
Sam Adamsh

0

Se la classe è ereditata, chiamare getInstance () da child non ti darà un'istanza di child. Restituirà solo un'istanza dell'istanza padre. Questo perché chiamiamo new self ().

Se si desidera che la classe figlia restituisca un'istanza della classe figlia, utilizzare new static () in getInstance () e restituirà l'istanza della classe figlia. Questo si chiama associazione tardiva !!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.