Quelle est la différence entre self :: $ bar et static :: $ bar en PHP?

125

Quelle est la différence entre utiliser selfet staticdans l'exemple ci-dessous?

class Foo
{
    protected static $bar = 1234;

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

}

Foo::instance();

produit

1234
1234
cwd
la source
2
@deceze: C'est une question similaire, mais ce n'est pas un doublon. Celui-ci demande comment utiliser les mots-clés avec les propriétés, tandis que celui-ci demande comment les utiliser avec les constructeurs.
BoltClock

Réponses:

191

Lorsque vous utilisez selfpour faire référence à un membre de classe, vous faites référence à la classe dans laquelle vous utilisez le mot-clé. Dans ce cas, votre Fooclasse définit une propriété statique protégée appelée $bar. Lorsque vous utilisez selfdans la Fooclasse pour faire référence à la propriété, vous faites référence à la même classe.

Par conséquent, si vous avez essayé d'utiliser self::$barailleurs dans votre Fooclasse mais que vous aviez une Barclasse avec une valeur différente pour la propriété, elle utiliserait à la Foo::$barplace de Bar::$bar, ce qui n'est peut-être pas ce que vous prévoyez:

class Foo
{
    protected static $bar = 1234;
}

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

Lorsque vous appelez une méthode via static, vous invoquez une fonctionnalité appelée liaisons statiques tardives (introduite dans PHP 5.3).

Dans le scénario ci-dessus, l'utilisation selfentraînera Foo::$bar(1234). Et l'utilisation staticdonnera Bar::$bar(4321) car avec static, l'interpréteur prend en compte la redéclaration au sein de la Barclasse lors de l'exécution.

Vous utilisez généralement des liaisons statiques tardives pour les méthodes ou même la classe elle-même, plutôt que des propriétés, car vous ne redéclarez pas souvent les propriétés dans les sous-classes; un exemple d'utilisation du staticmot - clé pour appeler un constructeur à liaison tardive peut être trouvé dans cette question connexe: New self vs. new static

Cependant, cela n'empêche pas non plus d'utiliser staticavec des propriétés.

BoltClock
la source
Vous pouvez très facilement redéclarer dans la classe enfant, la classe parente peut être une valeur par défaut que la classe enfant utilise à moins qu'elle ne se re-déclare. Si vous êtes dans la classe parente, je suppose qu'il est sûr d'utiliser self ::, et si vous êtes dans une classe enfant, vous pouvez trouver un argument pour utiliser l'un ou l'autre, mais self :: fonctionnera également si vous ne vous attendez pas à re-déclarer jamais.
Andrew
3
allez sur phpfiddle.org et exécutez ceci<?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
Le libellé des deux premiers paragraphes prête à confusion, a un pronom ambigu, «il», et est également redondant, car un paragraphe ultérieur explique plus clairement la même information. Je suggère de remplacer les deux premiers paragraphes par le dernier paragraphe commençant par «Dans le scénario ci-dessus» vers le haut. De cette façon, la réponse de bout en bout est en haut. C'est clair et facile à suivre.
ahnbizcad
Une autre façon de penser à cela:, self::$abclorsqu'il est utilisé à l'intérieur, class Fooc'est la même chose que de dire Foo::$abc. Il ne sera affecté par aucune re-déclaration de $abcdans une sous-classe. AFAIK, la seule raison à utiliser selfest en tant que raccourci, pour éviter d'utiliser le nom de la classe Foo, qui peut être plus long. [Cela signifie également que vous pouvez changer le nom de la classe sans changer tous ces endroits - mais ce n'est pas vraiment une raison à mon humble avis.] (Le choix des noms par PHP est malheureux et semble à l'envers; "statique" est celui qui peut changer - ce qui est opposé à la signification familière du mot «statique» en langage naturel.)
ToolmakerSteve
4

Comme mentionné, l'une des principales différences est qu'elle staticpermet des liaisons statiques tardives. L'un des scénarios les plus utiles que j'ai trouvés était pour la création de classes de base pour les classes 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

En utilisant return static::$name dans la classe Base renverra ce qui était attaché statiquement lors de son extension. Si vous deviez utiliser return self::$namealors B::getName()renverrait une chaîne vide comme c'est ce qui est déclaré dans la classe de base.

ggedde
la source
0

Avec selfappel:

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();

Vous pouvez voir ci-dessus, même si nous avons remplacé le $varavec notre Barclasse, il renvoie toujours 123, car nous avons explicitement demandé à PHP la selfvariable, qui à son tour demande la Foovariable s à la place.

Maintenant, si nous échangeons l'appel avec static, nous obtiendrons à la place la Barvaleur remplacée:

Avec staticappel:

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();
Steve Bauman
la source