Qual è la differenza tra self :: $ bar e static :: $ bar in PHP?


125

Qual è la differenza tra l'utilizzo selfe staticnell'esempio seguente?

class Foo
{
    protected static $bar = 1234;

    public static function instance()
    {
        echo self::$bar;
        echo "\n";
        echo static::$bar;
    }

}

Foo::instance();

produce

1234
1234

2
@deceze: Questa è una domanda simile, ma non è un duplicato. Questo chiede di usare le parole chiave con le proprietà, mentre quello chiede di usarle con i costruttori.
BoltClock

Risposte:


191

Quando usi selfper fare riferimento a un membro della classe, ti riferisci alla classe all'interno della quale usi la parola chiave. In questo caso, la tua Fooclasse definisce una proprietà statica protetta chiamata $bar. Quando si utilizza selfnella Fooclasse per fare riferimento alla proprietà, si fa riferimento alla stessa classe.

Pertanto, se hai provato a utilizzare self::$baraltrove nella tua Fooclasse ma avevi una Barclasse con un valore diverso per la proprietà, userebbe Foo::$barinvece di Bar::$bar, che potrebbe non essere quello che intendi:

class Foo
{
    protected static $bar = 1234;
}

class Bar extends Foo
{
    protected static $bar = 4321;
}

Quando chiami un metodo tramite static, stai invocando una funzionalità chiamata binding statico tardivo (introdotto in PHP 5.3).

Nello scenario precedente, l'utilizzo selfrisulterà in Foo::$bar(1234). E l'utilizzo staticrisulterà in Bar::$bar(4321) perché con static, l'interprete tiene conto della ridichiarazione all'interno della Barclasse durante il runtime.

In genere si utilizzano collegamenti statici tardivi per i metodi o anche per la classe stessa, piuttosto che per le proprietà, poiché spesso non si dichiarano nuovamente le proprietà nelle sottoclassi; un esempio di utilizzo della staticparola chiave per invocare un costruttore ad associazione tardiva può essere trovato in questa domanda correlata: New self vs. new static

Tuttavia, ciò non preclude l'utilizzo anche staticcon le proprietà.


Potresti ridichiarare molto facilmente nella classe figlia, la classe genitore potrebbe essere un valore predefinito che la classe figlia usa a meno che non si dichiari nuovamente. Se sei nella classe genitore, immagino sia sicuro usare self ::, e se in una classe figlio, potresti trovare un argomento per usare uno dei due, ma self :: funzionerà anche se non te lo aspetti dichiarare nuovamente mai.
Andrew

3
vai su phpfiddle.org ed esegui questo<?php class Foo { public static $bar = 1234; public static function a( ) { echo 'static'.static::$bar; echo 'self'.self::$bar; } } class Bar extends Foo { public static $bar = 4321; } (new Bar())->a(); ?>
Yevgeniy Afanasyev

2
La formulazione dei primi due paragrafi è confusa, ha un pronome ambiguo, "it", ed è anche ridondante, poiché i paragrafi successivi spiegano le stesse informazioni più chiaramente. Suggerisco di sostituire i primi due paragrafi con il paragrafo successivo che inizia con "Nello scenario precedente" all'inizio. In questo modo la linea di fondo, la risposta immediata è in cima. È chiaro e facile da seguire.
ahnbizcad

Un altro modo di pensare a questo:, self::$abcse usato all'interno class Fooè lo stesso che dire Foo::$abc. Non sarà influenzato da alcuna ri-dichiarazione di $abcin una sottoclasse. Per quanto ne so, l'unico motivo per utilizzare selfè come abbreviazione, per evitare di utilizzare il nome della classe Foo, che potrebbe essere più lungo. [Significa anche che puoi cambiare il nome della classe senza cambiare tutte quelle posizioni - ma questo non è un motivo importante per IMHO.] (La scelta dei nomi di PHP è sfortunata e sembra al contrario; "statico" è quello che può cambiare - che è opposto al significato colloquiale della parola in linguaggio naturale "statico".)
ToolmakerSteve

4

Come accennato, una delle principali differenze è che staticconsente attacchi statici tardivi. Uno degli scenari più utili che ho trovato era per la creazione di classi Base per classi Singleton:

class A { // Base Class
    protected static $name = '';
    protected static function getName() {
        return static::$name;
    }
}
class B extends A {
    protected static $name = 'MyCustomNameB';
}
class C extends A {
    protected static $name = 'MyCustomNameC';
}

echo B::getName(); // MyCustomNameB
echo C::getName(); // MyCustomNameC

L'utilizzo return static::$namenella classe Base restituirà ciò che era staticamente allegato quando è stato esteso. Se si sceglie di usare return self::$nameallora B::getName()restituirebbe una stringa vuota come questo è ciò che viene dichiarato nella classe Base.


0

Con selfchiamata:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return self::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "123"
echo (new Bar)->getVar();

Puoi vedere sopra, anche se abbiamo sovrascritto il $varcon la nostra Barclasse, ritorna ancora 123, perché abbiamo chiesto esplicitamente a PHP la selfvariabile, che a sua volta richiede Fooinvece la variabile s.

Ora, se scambiamo la chiamata con static, otterremo invece Baril valore s sovrascritto:

Con staticchiamata:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return static::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "234"
echo (new Bar)->getVar();
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.