Nouveau soi contre nouveau statique

513

Je convertis une bibliothèque PHP 5.3 pour travailler sur PHP 5.2. La principale chose qui me gêne est l'utilisation de la liaison statique tardive return new static($options);, si je convertis cela pour return new self($options)obtenir les mêmes résultats?

Quelle est la difference entre new selfet new static?

Mike
la source

Réponses:

891

vais-je obtenir les mêmes résultats?

Pas vraiment. Je ne connais pas de solution de contournement pour PHP 5.2, cependant.

Quelle est la difference entre new selfet new static?

selffait référence à la même classe dans laquelle le newmot clé est réellement écrit.

static, dans les dernières liaisons statiques de PHP 5.3, fait référence à la classe de la hiérarchie sur laquelle vous avez appelé la méthode.

Dans l'exemple suivant, Bhérite des deux méthodes de A. L' selfinvocation est liée à Acar elle est définie dans Al'implémentation de la première méthode, tandis qu'elle staticest liée à la classe appelée (voir aussi get_called_class()).

class A {
    public static function get_self() {
        return new self();
    }

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

class B extends A {}

echo get_class(B::get_self());  // A
echo get_class(B::get_static()); // B
echo get_class(A::get_self()); // A
echo get_class(A::get_static()); // A
BoltClock
la source
logique. Je pense que le meilleur pari est de passer le nom de la classe à la fonction qui utilise la liaison statique tardive, puis de renvoyer le nouveau $ className ($ options);
Mike
12
Vous n'avez pas à "passer" le nom de la classe, vous pouvez toujours le faire get_called_class(), ce qui est en fait le même que __CLASS__, mais compatible LSB.
shadowhand
7
get_called_class n'existe pas dans <PHP5.3. Par conséquent, si vous souhaitez obtenir le nom de classe de l'objet instancié en PHP5.2 Cette fonction n'aide pas lorsque vous essayez de convertir une bibliothèque de PHP 5.3 en PHP 5.2
txwikinger
2
La fonction appelée self :: theFunction () se comporte comme "Je vais exécuter dans le contexte de la classe à laquelle j'appartiens physiquement." et la fonction appelée static :: theFunction () se comporte comme "je vais exécuter dans le contexte de la classe qui a été effectivement appelée par le monde extérieur". (En supposant le scénario d'héritage). Merci
Shubhranshu
2
Dans ma tête, je prends tout ce qui est intuitif et je fais le contraire. On pourrait penser en fonction de la dénomination, selfserait lui - même revenir, et staticretourne quelque chose qui ne peut pas être surchargée ... Mais voilà que c'est le contraire. Je ne cesse d'être impressionné par la dénomination, les conventions et le style général de PHP. -_-
ahnbizcad
23

Si la méthode de ce code n'est pas statique, vous pouvez obtenir une solution de contournement en 5.2 en utilisant get_class($this).

class A {
    public function create1() {
        $class = get_class($this);
        return new $class();
    }
    public function create2() {
        return new static();
    }
}

class B extends A {

}

$b = new B();
var_dump(get_class($b->create1()), get_class($b->create2()));

Les resultats:

string(1) "B"
string(1) "B"
Marius Balčytis
la source
17
Si la méthode n'est pas statique, les liaisons statiques tardives deviennent totalement hors de propos.
BoltClock
1
Par exemple, vous pouvez l'utiliser dans la méthode "copier", où l'objet est copié sans utiliser clone, mais simplement en recréant et en définissant les propriétés. $copy = new static(); $copy->set($this->get()); return $copy;
Marius Balčytis
9
@BoltClock Sûrement pas? Si vous appelez une méthode statique remplacée à partir d'une méthode d'instance d'une sous-classe, votre choix self::ou static::va affecter si la version de la classe de base ou de la sous-classe de cette méthode statique est utilisée. En l’absence de toute raison de penser qu’une telle situation se produise par nature comme une mauvaise pratique (et je ne vois aucune raison pour laquelle il devrait en être ainsi), le choix entre self::et static::est tout aussi pertinent dans les méthodes non statiques que dans méthodes statiques. Ai-je mal compris votre commentaire, ou est-ce que nous nous trompons tout simplement?
Mark Amery
4
@Mark Amery: Hmm je n'y ai pas pensé. Vous avez absolument raison. J'avais supposé qu'aucune méthode statique n'allait être appelée dans la méthode d'instance en question, mais d'après votre exemple, je peux voir comment ce serait une hypothèse très naïve.
BoltClock
Liaisons statiques tardives doc => php.net/manual/en/language.oop5.late-static-bindings.php
DevWL
7

En plus des réponses des autres:

static :: sera calculé en utilisant les informations d'exécution.

Cela signifie que vous ne pouvez pas utiliser static::dans une propriété de classe car les valeurs des propriétés:

Doit pouvoir être évalué au moment de la compilation et ne doit pas dépendre des informations d'exécution.

class Foo {
    public $name = static::class;

}

$Foo = new Foo;
echo $Foo->name; // Fatal error

En utilisant self::

class Foo {
    public $name = self::class;

}
$Foo = new Foo;
echo $Foo->name; // Foo

Veuillez noter que le commentaire d'erreur fatale dans le code que j'ai fait n'indique pas où l'erreur s'est produite, l'erreur s'est produite plus tôt avant que l'objet ne soit instancié comme @Grapestain mentionné dans les commentaires

Pluie
la source
4
Notez que l'erreur est renvoyée sur la ligne 2 public $name = static::class;, pas sur la ligne 7, comme le suggère l'exemple. L'erreur indique: "static :: class ne peut pas être utilisé pour la résolution de nom de classe au moment de la compilation", ce qui indique que le problème n'est pas là où vous essayez d'accéder au champ $ name, mais bien avant, lors de la compilation de la classe PHP. La ligne 7 (ou 6) ne sera pas atteinte dans le premier exemple.
sbnc.eu
@Grapestain Le commentaire que j'ai fait dans l'exemple était de montrer le résultat final et non d'indiquer où l'erreur s'est réellement produite. Mais de toute façon merci de l'avoir signalé.
Pluie
Bon, je ne voulais pas critiquer, j'ai juste clarifié ce qui m'a dérouté en premier dans l'espoir que cela puisse aider les autres. Un exemple utile quand même!
sbnc.eu