Quando usare self oltre $ this?


Risposte:


1728

Risposta breve

Utilizzare $thisper fare riferimento all'oggetto corrente. Utilizzare selfper fare riferimento alla classe corrente. In altre parole, utilizzare $this->memberper membri non statici, utilizzare self::$memberper membri statici.

Risposta completa

Ecco un esempio di utilizzo corretto di $thise selfper variabili membro non statiche e statiche:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?>

Ecco un esempio di utilizzo errato di $thise selfper variabili membro non statiche e statiche:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo self::$non_static_member . ' '
           . $this->static_member;
    }
}

new X();
?>

Ecco un esempio di polimorfismo con $thisfunzioni membro:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        $this->foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

Ecco un esempio di soppressione del comportamento polimorfico usando selfper le funzioni membro:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        self::foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

L'idea è che $this->foo()chiama la foo()funzione membro di qualunque sia il tipo esatto dell'oggetto corrente. Se l'oggetto è di type X, quindi chiama X::foo(). Se l'oggetto è di type Y, chiama Y::foo(). Ma con self :: foo (), X::foo()viene sempre chiamato.

Da http://www.phpbuilder.com/board/showthread.php?t=10354489 :

Di http://board.phpbuilder.com/member.php?145249-laserlight


330
Questa risposta è eccessivamente semplicistica. Come indicato in altre risposte, selfviene utilizzato con l'operatore di risoluzione dell'ambito ::per fare riferimento alla classe corrente; questo può essere fatto sia in contesti statici che non statici. Inoltre, è perfettamente legale utilizzare $thisper chiamare metodi statici (ma non per fare riferimento ai campi).
Artefacto,

50
Considera anche l'uso di static :: anziché :: self se sei su 5.3+. Potrebbe causare mal di testa non detto altrimenti, vedere la mia risposta qui sotto per il perché.
Sqoo,

25
-1. Questa risposta è fuorviante, leggi le altre risposte per maggiori informazioni.
Pacerier,

6
Può essere eccessivamente semplificato, ma ha risposto alla mia domanda di livello base senza far esplodere la testa. Ho ottenuto ulteriori informazioni che ho trovato utili più in basso, ma per ora stavo solo cercando di capire perché ho colpito gli attributi della mia classe con $ this-> attrib e le costanti della classe con self :: constant. Questo mi ha aiutato a capirlo meglio
MydKnight

Che dire $this::?
James,

742

La parola chiave self NON si riferisce semplicemente alla "classe corrente", almeno non in un modo che ti limiti ai membri statici. Nel contesto di un membro non statico, selffornisce anche un modo per bypassare la vtable ( vedere wiki su vtable ) per l'oggetto corrente. Proprio come puoi usare parent::methodName()per chiamare la versione genitore di una funzione, così puoi chiamare self::methodName()per chiamare l'implementazione delle classi corrente di un metodo.

class Person {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }

    public function getTitle() {
        return $this->getName()." the person";
    }

    public function sayHello() {
        echo "Hello, I'm ".$this->getTitle()."<br/>";
    }

    public function sayGoodbye() {
        echo "Goodbye from ".self::getTitle()."<br/>";
    }
}

class Geek extends Person {
    public function __construct($name) {
        parent::__construct($name);
    }

    public function getTitle() {
        return $this->getName()." the geek";
    }
}

$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();

Questo produrrà:

Ciao, sono Ludwig il geek
Addio da Ludwig la persona

sayHello()usa il $thispuntatore, quindi la vtable viene invocata per chiamare Geek::getTitle(). sayGoodbye()usa self::getTitle(), quindi la vtable non viene utilizzata e Person::getTitle()viene chiamata. In entrambi i casi, abbiamo a che fare con il metodo di un oggetto istanziato e abbiamo accesso al $thispuntatore all'interno delle funzioni chiamate.


3
Questa risposta sarebbe ancora migliore se iniziassi con una regola generale piuttosto che un'eccezione. È una questione di stile, non di competenza tecnica. Questo è il miglior esempio che io abbia mai visto della differenza tra self :: e $ this->, ma è un peccato nasconderlo smentendo prima una nozione.
adjwilli,

3
@adjwilli: Perché è quello stile cattivo? Non aumenta la consapevolezza se l'attesa (tesi) dell'OP viene prima disapprovata (antitesi) e poi la spiegazione viene data come sintesi?
hakre,

1
Trovo che la "classe attuale" sia davvero problematica. Poiché quella combinazione di parole può essere intesa sia come "la classe in cui selfsi trova" / "la definizione della classe, è una parte letterale di" sia "la classe dell'oggetto" (che in realtà sarebbe static).
Jakumi,

Che dire $this::?
James,

1
@James - non c'è una buona ragione per usare $this::; tutti i possibili casi sono già coperti da sintassi più comunemente utilizzate. A seconda di quello che vuoi dire, l'uso $this->, self::o static::.
ToolmakerSteve

460

NON USARE self::, usarestatic::

C'è un altro aspetto di sé: che vale la pena menzionare. Si self::riferisce fastidiosamente al campo di applicazione al punto di definizione, non al punto di esecuzione . Considera questa semplice classe con due metodi:

class Person
{

    public static function status()
    {
        self::getStatus();
    }

    protected static function getStatus()
    {
        echo "Person is alive";
    }

}

Se chiamiamo Person::status()vedremo "La persona è viva". Ora considera cosa succede quando creiamo una classe che eredita da questo:

class Deceased extends Person
{

    protected static function getStatus()
    {
        echo "Person is deceased";
    }

}

Chiamando Deceased::status()ci aspetteremmo di vedere "La persona è deceduta", tuttavia ciò che vediamo è "La persona è viva" poiché l'ambito contiene la definizione del metodo originale quando è self::getStatus()stata definita la chiamata a .

PHP 5.3 ha una soluzione. l' static::operatore di risoluzione implementa "associazione statica tardiva", che è un modo elegante per dire che è legato all'ambito della classe chiamata. Modificare la riga in status()a static::getStatus()ed i risultati sono ciò che ci si aspetterebbe. Nelle versioni precedenti di PHP dovrai trovare un kludge per farlo.

Vedi documentazione PHP

Quindi per rispondere alla domanda non come chiesto ...

$this->si riferisce all'oggetto corrente (un'istanza di una classe), mentre si static::riferisce a una classe


6
Che dire delle costanti di classe?
Kevin Bond,

53
"Chiamando il defunto :: status () ci aspetteremmo di vedere" La persona è deceduta "". No. Questa è una chiamata di funzione statica, quindi non è coinvolto il polimorfismo.
cquezel,

2
Di tutti i difetti di PHP, io per primo non penso che sia pazzesco. In quale altro modo consentirebbero ai programmatori di designare metodi sulla classe corrente (invece di cercarli nella vtable)? Se lo avessero chiamato in modo diverso (forse con caratteri di sottolineatura), le persone che vogliono questa caratteristica lo criticherebbero per essere brutta. Altrimenti, qualunque sia il nome sano che potrebbero usare sembra che ci sarebbero sempre persone facilmente confuse che lo criticherebbero per essere un comportamento "folle", probabilmente ignaro di come funziona anche l'invio di metodi.
TNE

2
L'esempio mi sembra confuso: vedo il getStatusmetodo come uno che chiamerei un'istanza di classe, non una classe.
Jānis Elmeris,

1
@Sqoo - dicendo "NON UTILIZZARE self ::, use static ::" è un punto strano da fare - quelli non sono deliberatamente la stessa operazione. Penso che il punto che stai davvero sollevando sia "è più chiaro se usi il nome della classe attuale" MyClass :: ", piuttosto che" self :: " . Cioè, se vuoi il comportamento di self::, puoi ottenerlo, meno confusamente, usando il nome specifico della classe, ad es MyClass::.
ToolmakerSteve

248

Per capire veramente di cosa stiamo parlando quando parliamo di selfcontro $this, dobbiamo davvero scavare in quello che sta succedendo a livello concettuale e pratico. Non credo che nessuna delle risposte lo faccia in modo appropriato, quindi ecco il mio tentativo.

Cominciamo parlando di cosa sono una classe e un oggetto .

Classi e oggetti, concettualmente

Allora, che cosa è un codice categoria ? Molte persone lo definiscono come un progetto o un modello per un oggetto. In effetti, puoi leggere di più sulle classi in PHP qui . E fino a un certo punto è così. Diamo un'occhiata a una classe:

class Person {
    public $name = 'my name';
    public function sayHello() {
        echo "Hello";
    }
}

Come puoi vedere, esiste una proprietà su quella classe chiamata $namee un metodo (funzione) chiamato sayHello().

È molto importante notare che la classe è una struttura statica. Ciò significa che la classe Person, una volta definita, è sempre la stessa ovunque la guardi.

Un oggetto d'altra parte è ciò che viene chiamato un'istanza di una classe. Ciò significa che prendiamo il "progetto" della classe e lo usiamo per fare una copia dinamica. Questa copia ora è specificamente legata alla variabile in cui è archiviata. Pertanto, qualsiasi modifica a un'istanza è locale a tale istanza.

$bob = new Person;
$adam = new Person;
$bob->name = 'Bob';
echo $adam->name; // "my name"

Creiamo nuove istanze di una classe utilizzando l' newoperatore.

Pertanto, diciamo che una classe è una struttura globale e un oggetto è una struttura locale. Non preoccuparti di quella ->sintassi divertente , ci entreremo tra poco.

Un'altra cosa di cui dovremmo parlare è che possiamo verificare se un'istanza è una instanceofclasse particolare: $bob instanceof Personche restituisce un valore booleano se l' $bobistanza è stata creata usando la Personclasse, o un figlio di Person.

Definire lo stato

Quindi scaviamo un po 'in ciò che effettivamente contiene una classe. Esistono 5 tipi di "cose" che una classe contiene:

  1. Proprietà : pensa a queste come variabili che ogni istanza conterrà.

    class Foo {
        public $bar = 1;
    }
  2. Proprietà statiche - Pensa a queste come variabili condivise a livello di classe. Ciò significa che non vengono mai copiati da ciascuna istanza.

    class Foo {
        public static $bar = 1;
    }
  3. Metodi : sono funzioni che ogni istanza conterrà (e opererà su istanze).

    class Foo {
        public function bar() {}
    }
  4. Metodi statici : si tratta di funzioni condivise nell'intera classe. Essi non operano su istanze, ma invece sul solo le proprietà statiche.

    class Foo {
        public static function bar() {}
    }
  5. Costanti : costanti risolte in classe. Non andare più in profondità qui, ma aggiungendo per completezza:

    class Foo {
        const BAR = 1;
    }

Quindi, in sostanza, stiamo memorizzando informazioni sulla classe e sul contenitore oggetti usando "suggerimenti" su static che identificano se le informazioni sono condivise (e quindi statiche) o meno (e quindi dinamiche).

Stato e metodi

All'interno di un metodo, l'istanza di un oggetto è rappresentata dalla $thisvariabile. Lo stato corrente di quell'oggetto è presente e la mutazione (modifica) di qualsiasi proprietà comporterà una modifica a quell'istanza (ma non ad altre).

Se un metodo viene chiamato staticamente, la $thisvariabile non è definita . Questo perché non esiste un'istanza associata a una chiamata statica.

La cosa interessante qui è come vengono fatte le chiamate statiche. Quindi parliamo di come accediamo allo stato:

Stato di accesso

Quindi ora che abbiamo memorizzato quello stato, dobbiamo accedervi. Questo può diventare un po 'complicato (o molto più di un po'), quindi dividiamolo in due punti di vista: dall'esterno di un'istanza / classe (diciamo da una normale chiamata di funzione o dall'ambito globale) e all'interno di un'istanza / class (dall'interno di un metodo sull'oggetto).

Dall'esterno di un'istanza / classe

Dall'esterno di un'istanza / classe, le nostre regole sono abbastanza semplici e prevedibili. Abbiamo due operatori e ognuno ci dice immediatamente se abbiamo a che fare con un'istanza o una classe statica:

  • ->- object-operator : viene sempre utilizzato quando si accede a un'istanza.

    $bob = new Person;
    echo $bob->name;

    È importante notare che la chiamata Person->foonon ha senso (poiché Personè una classe, non un'istanza). Pertanto, questo è un errore di analisi.

  • :: - scope-risoluzione-operatore : viene sempre utilizzato per accedere a una proprietà o un metodo statici di classe.

    echo Foo::bar()

    Inoltre, possiamo chiamare un metodo statico su un oggetto allo stesso modo:

    echo $foo::bar()

    È estremamente importante notare che quando lo facciamo dall'esterno , l'istanza dell'oggetto è nascosta dal bar()metodo. Ciò significa che è esattamente lo stesso della corsa:

    $class = get_class($foo);
    $class::bar();

Pertanto, $thisnon è definito nella chiamata statica.

Dall'interno di un'istanza / classe

Le cose cambiano un po 'qui. Vengono utilizzati gli stessi operatori, ma il loro significato diventa significativamente sfocato.

L' operatore oggetto -> viene ancora utilizzato per effettuare chiamate allo stato dell'istanza dell'oggetto.

class Foo {
    public $a = 1;
    public function bar() {
        return $this->a;
    }
}

Richiamare il bar()metodo su $foo(un'istanza di Foo) utilizzando l'operatore oggetto: $foo->bar()comporterà la versione dell'istanza di$a .

Quindi è così che ci aspettiamo.

Il significato ::dell'operatore però cambia. Dipende dal contesto della chiamata alla funzione corrente:

  • In un contesto statico

    In un contesto statico, anche tutte le chiamate effettuate utilizzando ::saranno statiche. Diamo un'occhiata a un esempio:

    class Foo {
        public function bar() {
            return Foo::baz();
        }
        public function baz() {
            return isset($this);
        }
    }

    Chiamando Foo::bar()chiamerà il baz()metodo statico, e quindi $thissarà non essere popolato. Vale la pena notare che nelle ultime versioni di PHP (5.3+) questo causerà un E_STRICTerrore, perché stiamo chiamando staticamente metodi non statici.

  • In un contesto di istanza

    D'altro canto, all'interno di un contesto di istanza, le chiamate effettuate tramite ::dipendono dal destinatario della chiamata (il metodo che stiamo chiamando). Se il metodo è definito comestatic , utilizzerà una chiamata statica. In caso contrario, inoltrerà le informazioni sull'istanza.

    Quindi, guardando il codice sopra, la chiamata $foo->bar()tornerà true, poiché la chiamata "statica" avviene all'interno di un contesto di istanza.

Ha senso? Non la pensavo così. È confusionario.

Parole chiave di scelta rapida

Poiché legare tutto insieme usando i nomi delle classi è piuttosto sporco, PHP fornisce 3 parole chiave di base "scorciatoia" per facilitare la risoluzione dell'ambito.

  • self- Questo si riferisce al nome della classe corrente. Quindi self::baz()è lo stesso Foo::baz()della Fooclasse (qualsiasi metodo su di essa).

  • parent - Questo si riferisce al genitore della classe corrente.

  • static- Questo si riferisce alla classe chiamata. Grazie all'ereditarietà, le classi figlio possono sovrascrivere metodi e proprietà statiche. Quindi chiamarli usando staticinvece di un nome di classe ci consente di risolvere da dove proviene la chiamata, piuttosto che il livello corrente.

Esempi

Il modo più semplice per capirlo è iniziare a guardare alcuni esempi. Scegliamo un corso:

class Person {
    public static $number = 0;
    public $id = 0;
    public function __construct() {
        self::$number++;
        $this->id = self::$number;
    }
    public $name = "";
    public function getName() {
        return $this->name;
    }
    public function getId() {
        return $this->id;
    }
}

class Child extends Person {
    public $age = 0;
    public function __construct($age) {
        $this->age = $age;
        parent::__construct();
    }
    public function getName() {
        return 'child: ' . parent::getName();
    }
}

Ora, stiamo anche guardando l'eredità qui. Ignora per un momento che questo è un cattivo modello a oggetti, ma diamo un'occhiata a cosa succede quando giochiamo con questo:

$bob = new Person;
$bob->name = "Bob";
$adam = new Person;
$adam->name = "Adam";
$billy = new Child;
$billy->name = "Billy";
var_dump($bob->getId()); // 1
var_dump($adam->getId()); // 2
var_dump($billy->getId()); // 3

Quindi il contatore ID è condiviso da entrambe le istanze e dai figli (perché stiamo usando selfper accedervi. Se lo usassimo static, potremmo sovrascriverlo in una classe figlio).

var_dump($bob->getName()); // Bob
var_dump($adam->getName()); // Adam
var_dump($billy->getName()); // child: Billy

Nota che stiamo eseguendo il metodo di Person::getName() istanza ogni volta. Ma stiamo usando ilparent::getName() per farlo in uno dei casi (il caso figlio). Questo è ciò che rende potente questo approccio.

Parola di cautela n. 1

Si noti che il contesto chiamante è ciò che determina se viene utilizzata un'istanza. Perciò:

class Foo {
    public function isFoo() {
        return $this instanceof Foo;
    }
}

Non è sempre vero.

class Bar {
    public function doSomething() {
        return Foo::isFoo();
    }
}
$b = new Bar;
var_dump($b->doSomething()); // bool(false)

Ora è davvero strano qui. Stiamo chiamando una classe diversa, ma quella $thische viene passata al Foo::isFoo()metodo è l'istanza di$bar .

Ciò può causare tutti i tipi di bug e concetti WTF concettuali. Così mi piacerebbe consiglio vivamente di evitare l' ::operatore all'interno di metodi di istanza su nulla, tranne quelle tre virtuali "scorciatoia" parole chiave ( static, self, eparent ).

Parola di attenzione # 2

Si noti che i metodi e le proprietà statici sono condivisi da tutti. Ciò li rende sostanzialmente variabili globali. Con tutti gli stessi problemi che derivano dai globali. Quindi esiterei davvero a conservare le informazioni in metodi / proprietà statici a meno che non ti senta a tuo agio nel fatto che siano veramente globali.

Parola di cautela n. 3

In generale, ti consigliamo di utilizzare il cosiddetto Late-Static-Binding utilizzando staticanziché self. Ma nota che non sono la stessa cosa, quindi dire "usa sempre staticinvece di selfè davvero miope. Invece, fermati e pensa alla chiamata che vuoi fare e pensa se vuoi che le classi secondarie siano in grado di scavalcare quella statica risolta chiamata.

TL / DR

Peccato, torna indietro e leggilo. Potrebbe essere troppo lungo, ma è così lungo perché questo è un argomento complesso

TL / DR # 2

Ok bene. In breve, selfviene utilizzato per fare riferimento al nome della classe corrente all'interno di una classe, dove come si $thisriferisce all'istanza dell'oggetto corrente . Si noti che selfè una scorciatoia copia / incolla. Puoi tranquillamente sostituirlo con il nome della tua classe e funzionerà benissimo. Ma$this è una variabile dinamica che non può essere determinata in anticipo (e potrebbe anche non essere la tua classe).

TL / DR # 3

Se viene utilizzato l'operatore oggetto ( ->), allora sai sempre che hai a che fare con un'istanza. Se viene utilizzato l'operatore di risoluzione dell'ambito ( ::), sono necessarie ulteriori informazioni sul contesto (siamo già in un contesto di oggetto? Siamo al di fuori di un oggetto? Ecc.).


1
Avvertenza n. 1: $ questo non verrà definito quando si chiama un metodo statico: 3v4l.org/9kr0e
Mark Achée,

Bene ... $thisnon sarà definito se segui "Standard rigorosi" e non chiami metodi staticamente che non sono definiti statici. Vedo il risultato che hai spiegato qui: 3v4l.org/WeHVM D'accordo, davvero strano.
Mark Achée,

2
Dopo aver letto completamente la lunga descrizione, mi sono sentito pigro scorrere di nuovo sopra per votarla. Scherzando, l'ho votato: D. Grazie è molto utile
Mr_Green

3
sarebbe bello aggiungere una chiara spiegazione della differenza tra self :: $ property e self :: property; Penso che sia anche abbastanza confuso
Tommaso Barbugli,

1
WoC # 1 si comporta diversamente dal PHP 7. Come Foo::isFoo()viene chiamato staticamente, $thisnon verrà definito. Questo è un comportamento più intuitivo secondo me. - Un altro risultato diverso è dato se Barsi dovesse estendere Foo. Quindi la chiamata Foo::isFoo()verrebbe effettivamente inserita nel contesto dell'istanza (non specifico di PHP7).
Kontrollfreak,

117

self(non $ self) si riferisce al tipo di classe, dove come si $thisriferisce all'istanza corrente della classe. selfè da utilizzare nelle funzioni membro statico per consentire l'accesso alle variabili membro statico. $thisviene utilizzato nelle funzioni membro non statiche ed è un riferimento all'istanza della classe su cui è stata chiamata la funzione membro.

Perché thisè un oggetto, lo usi come:$this->member

Poiché selfnon è un oggetto, è fondamentalmente un tipo che si riferisce automaticamente alla classe corrente, lo usi come:self::member


97

$this-> viene utilizzato per fare riferimento a un'istanza specifica delle variabili o dei metodi di una classe.

Example: 
$derek = new Person();

$ derek è ora un'istanza specifica di Person. Ogni persona ha un nome e un cognome, ma $ derek ha un nome e un cognome specifici (Derek Martin). All'interno dell'istanza $ derek, possiamo fare riferimento a quelli come $ this-> first_name e $ this-> last_name

ClassName :: è usato per fare riferimento a quel tipo di classe e alle sue variabili statiche, ai metodi statici. Se aiuta, puoi sostituire mentalmente la parola "statico" con "condiviso". Poiché sono condivisi, non possono fare riferimento a $ this, che fa riferimento a un'istanza specifica (non condivisa). Le variabili statiche (ovvero $ db_connection statico) possono essere condivise tra tutte le istanze di un tipo di oggetto. Ad esempio, tutti gli oggetti del database condividono una singola connessione (connessione $ statica).

Esempio di variabili statiche: fingiamo di avere una classe di database con una variabile a membro singolo: static $ num_connections; Ora, mettilo nel costruttore:

function __construct()
{
    if(!isset $num_connections || $num_connections==null)
    {
        $num_connections=0;
    }
    else
    {
        $num_connections++;
    }
}

Proprio come gli oggetti hanno costruttori, hanno anche i distruttori, che vengono eseguiti quando l'oggetto muore o non è impostato:

function __destruct()
{
    $num_connections--;
}

Ogni volta che creiamo una nuova istanza, aumenterà il nostro contatore di connessioni di una. Ogni volta che distruggiamo o smettiamo di usare un'istanza, il contatore delle connessioni diminuirà di uno. In questo modo, possiamo monitorare il numero di istanze dell'oggetto database che abbiamo in uso con:

echo DB::num_connections;

Poiché $ num_connections è statico (condiviso), rifletterà il numero totale di oggetti di database attivi. Potresti aver visto questa tecnica utilizzata per condividere le connessioni al database tra tutte le istanze di una classe di database. Questo perché la creazione della connessione al database richiede molto tempo, quindi è meglio crearne una sola e condividerla (questo si chiama Singleton Pattern).

I metodi statici (ad es. View statico pubblico :: format_phone_number ($ cifre)) possono essere utilizzati SENZA la prima istanza di uno di questi oggetti (ovvero non si riferiscono internamente a $ this).

Esempio di metodo statico:

public static function prettyName($first_name, $last_name)
{
    echo ucfirst($first_name).' '.ucfirst($last_name);
}

echo Person::prettyName($derek->first_name, $derek->last_name);

Come puoi vedere, la funzione statica pubblica prettyName non sa nulla sull'oggetto. Funziona solo con i parametri che passi, come una normale funzione che non fa parte di un oggetto. Perché preoccuparsi, quindi, se potessimo semplicemente non averlo come parte dell'oggetto?

  1. Innanzitutto, collegare le funzioni agli oggetti ti aiuta a mantenere le cose organizzate, in modo da sapere dove trovarle.
  2. In secondo luogo, impedisce conflitti di denominazione. In un grande progetto, è probabile che due sviluppatori creino funzioni getName (). Se uno crea un ClassName1 :: getName () e l'altro crea ClassName2 :: getName (), non è affatto un problema. Nessun conflitto. Yay metodi statici!

SELF :: Se stai codificando all'esterno dell'oggetto che ha il metodo statico a cui vuoi fare riferimento, devi chiamarlo usando il nome dell'oggetto View :: format_phone_number ($ phone_number); Se si esegue la codifica all'interno l'oggetto che ha il metodo statico si desidera fare riferimento, è possibile sia utilizzare il nome Vista :: format_phone_number dell'oggetto ($ pn), oppure è possibile utilizzare il self :: format_phone_number ($ pn) scorciatoia

Lo stesso vale per le variabili statiche: Esempio: View :: templates_path contro self :: templates_path

All'interno della classe DB, se ci riferissimo a un metodo statico di qualche altro oggetto, utilizzeremmo il nome dell'oggetto: Esempio: Session :: getUsersOnline ();

Ma se la classe DB volesse fare riferimento alla propria variabile statica, direbbe solo self: Esempio: self :: connection;

Spero che aiuti a chiarire le cose :)


Bella risposta. Voglio solo sottolineare, quando si fa riferimento a un attributo statico, è necessario utilizzare un $segno. Ad esempioself::$templates_path
henrywright il

30

Da questo post del blog :

  • self si riferisce alla classe corrente
  • self può essere utilizzato per chiamare funzioni statiche e fare riferimento a variabili membro statiche
  • self può essere utilizzato all'interno di funzioni statiche
  • self può anche disattivare il comportamento polimorfico bypassando la vtable
  • $this si riferisce all'oggetto corrente
  • $this può essere usato per chiamare funzioni statiche
  • $thisnon deve essere utilizzato per chiamare variabili membro statiche. Usa selfinvece.
  • $this non può essere utilizzato all'interno di funzioni statiche

26

In PHP, usi la parola chiave self per accedere a proprietà e metodi statici.

Il problema è che è possibile sostituire $this->method()con self::method()qualsiasi luogo, a prescindere se method()è dichiarato statico o no. Quindi quale dovresti usare?

Considera questo codice:

class ParentClass {
    function test() {
        self::who();    // will output 'parent'
        $this->who();   // will output 'child'
    }

    function who() {
        echo 'parent';
    }
}

class ChildClass extends ParentClass {
    function who() {
        echo 'child';
    }
}

$obj = new ChildClass();
$obj->test();

In questo esempio, self::who()verrà sempre generato 'parent', mentre $this->who()dipenderà dalla classe che ha l'oggetto.

Ora possiamo vedere che self si riferisce alla classe in cui viene chiamato, mentre si $thisriferisce alla classe dell'oggetto corrente .

Quindi, dovresti usare sé solo quando $this non è disponibile o quando non vuoi consentire alle classi discendenti di sovrascrivere il metodo corrente.


22

All'interno di una definizione di classe, si $thisriferisce all'oggetto corrente, mentreself riferisce alla classe corrente.

È necessario fare riferimento a un elemento di classe utilizzando selfe fare riferimento a un elemento oggetto utilizzando $this.

self::STAT // refer to a constant value
self::$stat // static variable
$this->stat // refer to an object variable  

21

Ecco un esempio dell'uso corretto di $ this e self per le variabili membro non statiche e statiche:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?> 

21

Secondo http://www.php.net/manual/en/language.oop5.static.php non esiste $self. C'è solo $this, per fare riferimento all'istanza corrente della classe (l'oggetto), e self, che può essere usato per riferirsi a membri statici di una classe. La differenza tra un'istanza di oggetto e una classe entra in gioco qui.


9
Suggerimento: leggi questa risposta quando inciampi sull'acido.
a20,

16

Credo che la domanda non fosse se si può chiamare il membro statico della classe chiamando ClassName::staticMember. La domanda era qual è la differenza tra l'utilizzo di self::classmembere $this->classmember.

Ad esempio, entrambi i seguenti esempi funzionano senza errori, sia che si usi self::o$this->

class Person{
    private $name;
    private $address;

    public function __construct($new_name,$new_address){
        $this->name = $new_name;
        $this->address = $new_address;
    }
}

class Person{
    private $name;
    private $address;
    public function __construct($new_name,$new_address){
        self::$name = $new_name;
        self::$address = $new_address;
    }
}

È particolarmente divertente che inizi la tua risposta con "Credo che la domanda non fosse se puoi chiamare il membro statico della classe chiamando ClassName :: staticMember. La domanda era qual è la differenza tra l'utilizzo di self :: classmember e $ this-> classmember" e quindi si procede a non mostrare alcuna differenza. In effetti, mostri un'istanza in cui le due opzioni funzionano in modo identico. -1
Buttle Butkus,

Tuttavia utile. L'ambito riguardava la risoluzione e questa parte non è chiara nel manuale di php. Lo trovo ancora utile
renoirb

2
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
K-Gun,

16

self fa riferimento alla classe corrente (in cui viene chiamata),

$thisfa riferimento all'oggetto corrente. Puoi usare statico invece di sé. Vedi l'esempio:

    class ParentClass {
            function test() {
                    self::which();  // output 'parent'
                    $this->which(); // output 'child'
            }

            function which() {
                    echo 'parent';
            }
    }

    class ChildClass extends ParentClass {
            function which() {
                    echo 'child';
            }
    }

    $obj = new ChildClass();
    $obj->test();

Uscita: figlio principale


16
  • Il puntatore oggetto $thisa si riferisce all'oggetto corrente.
  • Il valore della classe si staticriferisce all'oggetto corrente.
  • Il valore della classe si selfriferisce alla classe esatta in cui è stata definita.
  • Il valore della classe si parentriferisce al genitore della classe esatta in cui è stato definito.

Vedere l'esempio seguente che mostra il sovraccarico.

<?php

class A {

    public static function newStaticClass()
    {
        return new static;
    }

    public static function newSelfClass()
    {
        return new self;
    }

    public function newThisClass()
    {
        return new $this;
    }
}

class B extends A
{
    public function newParentClass()
    {
        return new parent;
    }
}


$b = new B;

var_dump($b::newStaticClass()); // B
var_dump($b::newSelfClass()); // A because self belongs to "A"
var_dump($b->newThisClass()); // B
var_dump($b->newParentClass()); // A


class C extends B
{
    public static function newSelfClass()
    {
        return new self;
    }
}


$c = new C;

var_dump($c::newStaticClass()); // C
var_dump($c::newSelfClass()); // C because self now points to "C" class
var_dump($c->newThisClass()); // C
var_dump($b->newParentClass()); // A because parent was defined *way back* in class "B"

Il più delle volte si desidera fare riferimento alla classe corrente, motivo per cui si utilizza statico $this. Tuttavia, ci sono momenti in cui è necessario self perché si desidera la classe originale indipendentemente da ciò che la estende. (Molto, Molto di rado)


14

Dato che qui nessuno parlava di performance, ecco un piccolo benchmark che ho fatto (5.6):

 Name     | Time    | Percent  
----------|---------|---------  
 $this->  | 0.99163 | 106.23%  
 self::   | 0.96912 | 103.82%  
 static:: | 0.93348 | 100%

Questi sono i risultati per 2 000 000 di esecuzioni ed ecco il codice che ho usato:

<?php

require '../vendor/autoload.php';

// My small class to do benchmarks
// All it does is looping over every test x times and record the
//   time it takes using `microtime(true)`
// Then, the percentage is calculated, with 100% being the quickest
// Times are being rouned for outputting only, not to calculate the percentages
$b = new Tleb\Benchmark\Benchmark(2000000);

class Foo
{
    public function calling_this()
    {
        $this->called();
    }

    public function calling_self()
    {
        self::called();
    }

    public function calling_static()
    {
        static::called();
    }

    public static function called()
    {
    }
}

$b->add('$this->',  function () { $foo = new Foo; $foo->calling_this(); });
$b->add('self::',   function () { $foo = new Foo; $foo->calling_self(); });
$b->add('static::', function () { $foo = new Foo; $foo->calling_static(); });

$b->run();

1
La chiamata alla funzione no-op 2 000 000 di volte dura 1 secondo. Devi amare PHP.
r-

Buon vecchio PHP. :) Ma una chiamata = 0,001 ms. È così male?
martedì

Credo che questo (e cose simili) sia il motivo per cui cose come gli ORM si sentono lenti a meno che non si memorizzi nella cache roba e i generatori di siti statici siano una cosa.
r-

2
Dovrebbe teoricamente richiedere 1 ciclo di clock del processore, che avviene in 1 / 2e9 s = 0.5 nsquesti giorni
Buddy,

Rileggi la mia risposta. Fai attenzione: crea anche la classe . Non so perché non ho usato la useparola chiave tbh, ma non ho più PHP per rifare un benchmark e non ho davvero voglia di reinstallarlo.
tleb

13

Quando selfviene utilizzato con l' ::operatore, si riferisce alla classe corrente, che può essere eseguita sia in contesti statici che non statici. $thissi riferisce all'oggetto stesso. Inoltre, è perfettamente legale utilizzare $thisper chiamare metodi statici (ma non fare riferimento ai campi).


8

Ho incontrato la stessa domanda e la risposta semplice è:

  • $this richiede un'istanza della classe
  • self:: non lo fa

Ogni volta che si utilizzano metodi statici o attributi statici e si desidera chiamarli senza avere un'istanza di un oggetto della classe, è necessario utilizzarli self:per chiamarli, poiché è $thissempre necessario creare l'oggetto.


7

$thissi riferisce all'oggetto classe corrente, si selfriferisce alla classe corrente (non oggetto). La classe è il progetto dell'oggetto. Quindi definisci una classe, ma costruisci oggetti.

Quindi, in altre parole, utilizzare self for staticethis for none-static members or methods .

anche nello scenario figlio / genitore self / parentviene utilizzato principalmente per identificare membri e metodi della classe figlio e genitore.


7

Inoltre da allora $this::non è stato ancora discusso.

Solo a scopo informativo, a partire da PHP 5.3 quando si ha a che fare con oggetti istanziati per ottenere il valore di ambito corrente, al contrario dell'uso static::, si può alternativamente usare $this::così.

http://ideone.com/7etRHy

class Foo
{
    const NAME = 'Foo';

    //Always Foo::NAME (Foo) due to self
    protected static $staticName = self::NAME;

    public function __construct()
    {
        echo $this::NAME;
    }

    public function getStaticName()
    {
       echo $this::$staticName;
    }
}

class Bar extends Foo
{
    const NAME = 'FooBar';

    /**
     * override getStaticName to output Bar::NAME
     */
    public function getStaticName()
    {
        $this::$staticName = $this::NAME;
        parent::getStaticName();
    }
}

$foo = new Foo; //outputs Foo
$bar = new Bar; //outputs FooBar
$foo->getStaticName(); //outputs Foo
$bar->getStaticName(); //outputs FooBar
$foo->getStaticName(); //outputs FooBar

L'uso del codice sopra non è una pratica comune o raccomandata, ma serve semplicemente a illustrarne l'uso e ad agire come qualcosa di più di "Lo sapevi?" in riferimento alla domanda del poster originale.

Rappresenta anche l'uso di $object::CONSTANTper esempio echo $foo::NAME;rispetto a$this::NAME;


5

Utilizzare selfse si desidera chiamare un metodo di una classe senza creare un oggetto / istanza di quella classe, risparmiando così la RAM (a volte usare self per quello scopo). In altre parole, in realtà sta chiamando staticamente un metodo. Utilizzare thisper la prospettiva dell'oggetto.


2

Caso 1: utilizzare self può essere utilizzato per le costanti di classe

 class classA { 
     const FIXED_NUMBER = 4; 
     self :: POUNDS_TO_KILOGRAMS
}

Se si desidera chiamarlo al di fuori della classe, utilizzare classA::POUNDS_TO_KILOGRAMSper accedere alle costanti

Caso 2: per proprietà statiche

class classC {
     funzione pubblica __construct () { 
     self :: $ _ contatore ++; $ this-> num = self :: $ _ counter;
   }
}

1

Secondo php.net ci sono tre parole chiave speciali in questo contesto: self, parente static. Sono utilizzati per accedere a proprietà o metodi dall'interno della definizione della classe.

$thisd'altra parte, viene utilizzato per chiamare un'istanza e metodi di qualsiasi classe purché tale classe sia accessibile.


-1

self ::  parola chiave utilizzata per la classe corrente e sostanzialmente viene utilizzata per accedere a membri, metodi e costanti statici. Ma nel caso di $ this non è possibile chiamare il membro, il metodo e le funzioni statici.

È possibile utilizzare la parola chiave self :: in un'altra classe e accedere ai membri, al metodo e alle costanti statici. Quando sarà esteso dalla classe genitore e lo stesso nel caso di $ questa parola chiave. È possibile accedere ai membri, al metodo e alla funzione non statici in un'altra classe quando verrà estesa dalla classe padre.

Il codice fornito di seguito è un esempio di self :: e $ questa parola chiave. Basta copiare e incollare il codice nel file di codice e vedere l'output.

class cars{
    var $doors=4;   
    static $car_wheel=4;

  public function car_features(){
    echo $this->doors." Doors <br>";
    echo self::$car_wheel." Wheels <br>"; 
  }
}

class spec extends cars{
    function car_spec(){
        print(self::$car_wheel." Doors <br>");
        print($this->doors." Wheels <br>");
    }
}

/********Parent class output*********/

$car = new cars;
print_r($car->car_features());

echo "------------------------<br>";

/********Extend class from another class output**********/


$car_spec_show=new spec;

print($car_spec_show->car_spec());
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.