Domanda Quando usarlo su $ this?


In PHP 5, qual è la differenza tra l'utilizzo self e $this?

Quando è appropriato?


1774
2017-09-30 06:23


origine


risposte:


Risposta breve

Uso $this per riferirsi alla corrente   oggetto. Uso self fare riferimento al   classe attuale. In altre parole, usa    $this->member per membri non statici,   uso self::$member per membri statici.

Risposta completa

Ecco un esempio di corretta utilizzo di $this e self per 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 scorretto utilizzo di $this e self per 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 $this per le funzioni dei membri:

<?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 sopprimere il comportamento polimorfico usando self per le funzioni dei membri:

<?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 è questa $this->foo() chiama il foo() la funzione membro di qualunque> è 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() è sempre chiamato.

A partire dal http://www.phpbuilder.com/board/showthread.php?t=10354489:

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


1507
2017-09-30 06:29



La parola chiave self fa NON si riferisce semplicemente alla "classe corrente", almeno non in un modo che limita i membri statici. Nel contesto di un membro non statico, self fornisce anche un modo per aggirare il vtable (vedi wiki su vtable) per l'oggetto corrente. Proprio come puoi usare parent::methodName() per chiamare la versione genitori di una funzione, in modo da poter chiamare self::methodName() chiamare l'implementazione delle classi correnti 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
     Arrivederci da Ludwig la persona

sayHello() usa il $this puntatore, quindi il vtable è invocato per chiamare Geek::getTitle(). sayGoodbye() usi self::getTitle(), quindi il vtable non è usato, e Person::getTitle() è chiamato. In entrambi i casi, abbiamo a che fare con il metodo di un oggetto istanziato e abbiamo accesso a $this puntatore all'interno delle funzioni chiamate.


710
2017-07-27 18:00



NON USARE self::, uso static::

C'è un altro aspetto di sé: vale la pena menzionarlo. fastidiosamente self:: si riferisce allo scopo al punto di definizione non al momento dell'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". Consideriamo ora cosa succede quando creiamo una classe che eredita da questo:

class Deceased extends Person
{

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

}

chiamata Deceased::status() ci aspetteremmo di vedere "Person is deceased", tuttavia quello che vediamo è "Person is alive" poiché l'ambito contiene la definizione del metodo originale quando si chiama self::getStatus() è stato definito.

PHP 5.3 ha una soluzione. il static:: l'operatore di risoluzione implementa "late static binding" che è un modo elegante per dire che è legato allo scope della classe chiamata. Cambia la linea in status() a static::getStatus() ed i risultati sono ciò che ti aspetteresti. Nelle versioni precedenti di PHP dovrai trovare un kludge per farlo.

Vedere Documentazione PHP

Quindi, per rispondere alla domanda non come chiesto ...

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


428
2017-07-24 15:08



Per capire veramente di cosa stiamo parlando quando parliamo self contro $this, abbiamo bisogno di scavare in realtà a cosa sta succedendo a livello concettuale e pratico. Non sento davvero nessuna delle risposte in modo appropriato, quindi ecco il mio tentativo.

Iniziamo parlando di ciò che a classe e un oggetto è.

Classi e oggetti, concettualmente

E allora è un classe? Un sacco di persone lo definiscono come un planimetria o a modello per un oggetto. In effetti, puoi leggere di più Informazioni sulle classi in PHP qui. E in un certo senso è quello che è veramente. Diamo un'occhiata a una classe:

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

Come puoi vedere, c'è una proprietà chiamata in quella classe $name e un metodo (funzione) chiamato sayHello().

Suo molto importante notare che il classe è una struttura statica. Il che significa che la classe Person, una volta definito, è sempre lo stesso ovunque lo guardi.

Un oggetto d'altra parte è ciò che viene chiamato un esempio 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 è memorizzata. Pertanto, qualsiasi modifica a esempio è locale per quell'istanza.

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

Creiamo nuovi casi di una classe usando il new operatore.

Pertanto, diciamo che una classe è una struttura globale e un oggetto è una struttura locale. Non preoccuparti di quello strano -> sintassi, ne parleremo tra un po '.

Un'altra cosa di cui dovremmo parlare, è che possiamo dai un'occhiata se un'istanza è un instanceof una classe particolare: $bob instanceof Person che restituisce un booleano se il $bob l'istanza è stata fatta usando il Person classe, o un figlio di Person.

Definizione dello stato

Quindi analizziamo un po 'quello che in realtà 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. Significa che non vengono mai copiati da ogni istanza.

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

    class Foo {
        public function bar() {}
    }
    
  4. Metodi statici - Queste sono funzioni che sono condivise attraverso l'intera classe. Loro fanno non operare su istanze, ma solo sulle proprietà statiche.

    class Foo {
        public static function bar() {}
    }
    
  5. costanti - Costanti risolte di classe. Non andare più a fondo qui, ma aggiungendo per completezza:

    class Foo {
        const BAR = 1;
    }
    

Quindi, fondamentalmente, stiamo memorizzando informazioni sulla classe e sul contenitore di oggetti usando "suggerimenti" statico che identificano se l'informazione è condivisa (e quindi statica) o meno (e quindi dinamica).

Stato e metodi

All'interno di un metodo, l'istanza di un oggetto è rappresentata dal $thisvariabile. Lo stato corrente di quell'oggetto è lì e, mutando (cambiando) qualsiasi proprietà, si otterrà una modifica a quell'istanza (ma non ad altre).

Se un metodo è chiamato staticamente, il $this variabile non è definito. 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:

Accesso allo stato

Quindi ora che abbiamo memorizzato quello stato, dobbiamo accedervi. Questo può diventare un po 'complicato (o modo più di un bit), dividiamo questo 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 / classe (all'interno di un metodo sul 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 statica di classe:

  • -> - oggetto-operatore - Questo è sempre usato quando stiamo accedendo a un'istanza.

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

    È importante notare che chiamare Person->foo non ha senso (dal Person è una classe, non un'istanza). Pertanto, questo è un errore di analisi.

  • :: - ambito risoluzione operatore - Viene sempre utilizzato per accedere a una proprietà o un metodo statico di classe.

    echo Foo::bar()
    

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

    echo $foo::bar()
    

    Suo estremamente importante notare che quando lo facciamo da fuori, l'istanza dell'oggetto è nascosta al bar() metodo. Significa che è la stessa della corsa:

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

Perciò, $this non è 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 molto sfocato.

Il oggetto-operatore  -> è ancora usato per effettuare chiamate allo stato dell'istanza dell'oggetto.

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

Chiamando il bar() metodo attivo $foo (un'istanza di Foo) utilizzando l'operatore oggetto: $foo->bar() risulterà nella versione dell'istanza di $a.

Ecco come ci aspettiamo.

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

  • All'interno di un contesto statico

    All'interno di un contesto statico, qualsiasi chiamata effettuata utilizzando :: sarà anche statico. Diamo un'occhiata a un esempio:

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

    chiamata Foo::bar() chiamerà il baz() metodo statico, e quindi $this volere non essere popolato. Vale la pena notare che nelle versioni recenti di PHP (5.3+) questo attiverà un E_STRICT errore, perché stiamo chiamando staticamente metodi non statici.

  • All'interno di un contesto di istanza

    All'interno di un contesto di istanza, d'altra parte, le chiamate effettuate utilizzando :: dipende dal destinatario della chiamata (il metodo che stiamo chiamando). Se il metodo è definito come static, quindi utilizzerà una chiamata statica. Se non lo è, inoltrerà le informazioni sull'istanza.

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

Ha senso? Non la penso così È confusionario.

Parole chiave scorciatoie

Poiché legare tutto insieme usando i nomi di classe è piuttosto sporco, PHP fornisce 3 parole chiave "di scelta rapida" di base per semplificare la risoluzione dell'ambito.

  • self - Questo si riferisce al nome della classe corrente. Così self::baz() equivale a Foo::baz() all'interno del Foo classe (qualsiasi metodo su di esso).

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

  • static - Questo si riferisce alla classe chiamata. Grazie all'ereditarietà, le classi figlie possono sovrascrivere metodi e proprietà statiche. Quindi chiamarli usando static invece 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 capire questo è iniziare a guardare alcuni esempi. Prendiamo una classe:

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 guardiamo anche all'eredità qui. Ignora per un momento che questo è un modello di oggetto scadente, ma guardiamo 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 tra entrambe le istanze e i bambini (perché stiamo usando self per accedervi. Se abbiamo usato static, potremmo scavalcarlo in una classe di bambini).

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

Si noti che stiamo eseguendo il Person::getName()  esempio metodo ogni volta. Ma stiamo usando il parent::getName() farlo in uno dei casi (il caso bambino). Questo è ciò che rende questo approccio potente.

Word Of Caution # 1

Si noti che il contesto di chiamata è 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 è veramente strano qui. Stiamo chiamando una classe diversa, ma il $this che viene passato al Foo::isFoo() metodo è l'istanza di $bar.

Questo può causare tutti i tipi di bug e WTF-ery concettuale. Quindi suggerirei caldamente di evitare il :: operatore da metodi di istanza su qualsiasi cosa tranne quelle tre parole chiave virtuali "scorciatoia" (static, self, e parent).

Word Of Caution # 2

Nota che i metodi e le proprietà statici sono condivisi da tutti. Questo li rende sostanzialmente variabili globali. Con tutti gli stessi problemi che vengono con i globals. Quindi sarei davvero riluttante a memorizzare le informazioni in metodi / proprietà statici a meno che non ti senta a tuo agio nel fatto che sia veramente globale.

Word Of Caution # 3

In generale, ti consigliamo di utilizzare ciò che è noto come Late-Static-Binding utilizzando static invece di self. Ma nota che non sono la stessa cosa, quindi dicendo "usa sempre static invece di self è davvero miope. Invece, fermati e pensa alla chiamata che vuoi fare e pensa se vuoi che le classi figlie siano in grado di scavalcarlo statico risolto chiamata.

TL / DR

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

TL / DR # 2

Ok bene. In breve, self è usato per fare riferimento il nome della classe attualeall'interno di una classe, dove come $this si riferisce all'oggetto corrente esempio. Nota che self è una scorciatoia copia / incolla. Puoi tranquillamente sostituirlo con il nome della tua classe, e funzionerà perfettamente. 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 lei sempre sai che hai a che fare con un'istanza. Se viene utilizzato l'operatore di risoluzione dell'ambito (::), hai bisogno di maggiori informazioni sul contesto (siamo già in un contesto oggetto? Siamo fuori da un oggetto? etc).


228
2018-06-10 15:21



self (non $ self) si riferisce al genere di classe, dove come $this si riferisce alla corrente esempio della classe. self è per l'uso in funzioni membro statiche per consentire l'accesso a variabili membro statiche. $this è usato in 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

Perché self non è un oggetto, è fondamentalmente un tipo che si riferisce automaticamente alla classe corrente, lo si usa come: self::member


109
2017-09-30 07:26



$this-> è usato per riferirsi a un'istanza specifica delle variabili di una classe (variabili membro) o metodi.

Example: 
$derek = new Person();

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

ClassName :: è usato per riferirsi a quel tipo di classe e alle sue variabili statiche, metodi statici. Se aiuta, puoi sostituire mentalmente la parola "statico" con "condiviso". Poiché sono condivisi, non possono fare riferimento a $ this, che si riferisce a un'istanza specifica (non condivisa). Le variabili statiche (ad esempio, $ db_connection) 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: Supponiamo di avere una classe di database con una variabile membro singola: stat $ $ num_connections; Ora, metti questo 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 dei distruttori, che vengono eseguiti quando l'oggetto muore o non è impostato:

function __destruct()
{
    $num_connections--;
}

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

echo DB::num_connections;

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

I metodi statici (ad esempio public static View :: format_phone_number ($ digit)) possono essere utilizzati SENZA prima istanziare uno di questi oggetti (ad esempio, non fanno riferimento 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 conosce nulla sull'oggetto. Funziona solo con i parametri che si passano, come una normale funzione che non fa parte di un oggetto. Perché preoccuparsi, quindi, se potessimo semplicemente averlo non come parte dell'oggetto?

  1. Innanzitutto, associare funzioni agli oggetti ti aiuta a mantenere le cose organizzate, così sai dove trovarle.
  2. Secondo, previene i conflitti di denominazione. In un grande progetto, è probabile che due sviluppatori creino le funzioni getName (). Se si crea un ClassName1 :: getName () e l'altro crea ClassName2 :: getName (), non c'è alcun problema. Nessun conflitto Yay metodi statici!

SE STESSO:: Se stai programmando al di fuori l'oggetto con il metodo statico a cui si desidera fare riferimento, è necessario chiamarlo utilizzando il nome dell'oggetto View :: format_phone_number ($ phone_number); Se stai programmando dentro l'oggetto con il metodo statico a cui si desidera fare riferimento, è possibile o usa il nome dell'oggetto View :: format_phone_number ($ pn), OPPURE puoi usare la scorciatoia self :: format_phone_number ($ pn)

Lo stesso vale per le variabili statiche: Esempio: Visualizza :: templates_path rispetto a self :: templates_path

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

Ma se la classe DB volesse riferirsi alla propria variabile statica, direbbe semplicemente self: Esempio: self :: connessione;

Spero che questo aiuti a chiarire le cose :)


93
2017-10-22 17:52



A partire dal questo post del blog:

  • self si riferisce alla classe corrente
  • self può essere usato 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 aggirando il vtable
  • $this si riferisce all'oggetto corrente
  • $this può essere usato per chiamare funzioni statiche
  • $this non dovrebbe essere usato per chiamare variabili membro statiche. Uso self anziché.
  • $this non può essere utilizzato all'interno di funzioni statiche

27
2018-05-10 12:00



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

Il problema è che puoi sostituire $this->method() con self::method()ovunque, indipendentemente 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() uscirà sempre 'genitore', mentre $this->who() dipenderà da quale classe ha l'oggetto.

Ora possiamo vedere che il sé si riferisce alla classe in cui è chiamato, mentre $this si riferisce a classe dell'oggetto corrente.

Quindi, dovresti usare self solo quando $this non è disponibile o quando non si desidera consentire alle classi discendenti di sovrascrivere il metodo corrente.


23
2017-12-29 13:20



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

È necessario fare riferimento a un elemento di classe usando self e fare riferimento a un elemento object usando $ this.

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

19
2018-05-08 06:58