Question

Si j'ai du code qui utilise un static variable à des fins de mise en cache comme celle-ci:

class BossParty
{
    // ...

    public function getTemplate()
    {
        static $template;

        if ($template == null)
        {
            $template = BossTemplate::get($this->templateID);
        }

        return $template;
    }

    // ...
}

Sera $template persistent à travers différents cas de BossParty? J'ai essayé de vérifier PHP.NET, mais tout ce que je peux trouver, ce sont des informations sur les variables de classe statique.

Était-ce utile?

La solution

Oui, la variable statique persistera sur les instances de la classe.

Exemple:

<?php

class Test {
    public function __construct() {
        static $foo;

        if ($foo) {
            echo 'found';
        } else {
            $foo = 'foobar';
        }
    }
}

$test1 = new Test();
$test2 = new Test();
// output "found"

Notez que cela est également vrai pour les classes descendantes. Si nous avions un cours Child qui s'est étendu Test, appelant parent::__construct (qu'il soit explicitement ou implicitement) utiliser la même valeur de $foo.

Autres conseils

@seul, cela semble être surtout correct. Cependant, en particulier lié à votre commentaire de suivi concernant l'héritage, le comportement de la portée de la variable statique à l'intérieur des fonctions semble être plus complexe. J'utilise PHP 5.3.16 pour tous mes exemples.

Le résumé: le comportement du static Mot-clé lorsqu'il est utilisé pour étendre une variable dans une fonction d'instance semble varier en fonction à la fois sur l'héritage et où vous êtes dans la pile d'appels de fonction.

Voici quelques exemples.

Tout d'abord, cela est similaire à votre exemple initial: instancier une variable statique dans le __construct() Méthode d'une classe, créez deux instances de cette classe et voyez comment cette variable se comporte.

<?php
// Example 1
class A {
  public function __construct() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
$o1 = new A();
$o2 = new A();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

Jusqu'à présent, aucune surprise. La variable est instanciée une fois (à 0) puis incrémentée avec chaque instance distincte.

Si vous étendez la classe A comme B, et instancier l'un de chacun (laissant tout le reste le même), vous obtenez le même comportement:

<?php
// Example 2
class A {
  public function __construct() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
class B extends A {}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

Encore une fois, aucune surprise. Revenons au premier exemple et ajustez-le un peu. Nous déplaçons d'abord l'appel d'instanciation / incrément de variable statique vers une méthode de membre. Notez que j'ai supprimé la classe B Pour celui-ci:

<?php
// Example 3
class A {
  public function __construct() {
    $this->setI();
  }

  public function setI() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
$o1 = new A();
$o2 = new A();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

Toujours la même sortie.

Cependant, quand vous étendez A comme B, et laisser la même structure en place:

<?php
// Example 4
class A {
  public function __construct() {
    $this->setI();
  }

  public function setI() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
class B extends A {}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 1"
?>

Notez la sortie: dans tous les autres cas, $o2->i est devenu 2, sauf pour celui-ci.

Il semble donc que si nous étendons A et Déplacez l'instanciation statique vers une méthode d'instance, nous semblons maintenant avoir introduit une nouvelle portée pour le $i Variable, tandis que dans tous les autres cas, les instances ont partagé une portée pour cette variable statique.

Encore plus déroutant, considérez cet exemple; C'est identique à la précédente, mais dans ce cas, la classe B obtient sa propre implémentation de setI(), qui cède simplement à l'implémentation de sa classe parent:

<?php
// Example 5
class A {
  public function __construct() {
    $this->setI();
  }
  public function setI() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
class B extends A {
  public function setI() {
    parent::setI();
  }
}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

Comme tu peux le voir, $o2->i est maintenant revenu à être réglé sur 2, ce que nous avons obtenu presque partout (sauf l'exemple n ° 4)

Pour moi, cela semble très contre-intuitif. Je m'attendrais à ce que Soit Différentes instances obtiennent leurs propres lunettes pour cette variable, ou Toutes les instances (y compris les instances de classes étendues) partagent la même portée.

Je ne peux pas dire s'il s'agit d'un bug en PHP, ou si c'est un comportement attendu. Les documents PHP sur la portée de la variable statique dire:

Une variable statique n'existe que dans une portée de fonction locale, mais elle ne perd pas sa valeur lorsque l'exécution du programme laisse cette portée.

Ils ne vont pas dans les détails de la définition de la «portée de la fonction» dans le contexte des instances d'objet, donc je ne sais pas si le cas de bord dans l'exemple n ° 4 est attendu ou non.

Oui, il est également documenté dans les documents, mais c'est sous la section Portée des variables à la place du Mot-clé statique, ce qui pourrait être la raison pour laquelle vous ne l'avez pas trouvé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top