Являются ли статические переменные в функциях в PHP глобальными для всех экземпляров? - PullRequest
5 голосов
/ 16 мая 2011

Если у меня есть код, который использует переменную static для целей кэширования, например:

class BossParty
{
    // ...

    public function getTemplate()
    {
        static $template;

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

        return $template;
    }

    // ...
}

Будет ли $template сохраняться в разных случаях BossParty?Я попытался проверить php.net, но все, что я могу найти, это информация о статических переменных класса.

Ответы [ 3 ]

7 голосов
/ 16 мая 2011

Да, статическая переменная будет сохраняться во всех экземплярах класса.

Пример:

<?php

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

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

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

Обратите внимание, что это верно и для классов-потомков. Если бы у нас был класс Child, который расширил Test, вызов parent::__construct (явно или неявно) будет использовать то же значение $foo.

2 голосов
/ 05 ноября 2012

@ Одинокий день , похоже, это в основном правильно. Однако, в частности, в связи с вашим последующим комментарием относительно наследования, поведение области действия статической переменной внутри функций выглядит более сложным. Я использую PHP 5.3.16 для всех моих примеров.

Сводка : поведение ключевого слова static при использовании для определения области действия переменной в экземпляре функции, кажется, зависит от наследования и от того, где вы находитесь в стеке вызовов функций.

Вот несколько примеров.

Во-первых, это похоже на ваш первоначальный пример: создать экземпляр статической переменной в методе __construct() класса, создать два экземпляра этого класса и посмотреть, как эта переменная ведет себя.

<?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"
?>

Пока никаких сюрпризов. Переменная создается один раз (до 0), а затем увеличивается с каждым отдельным экземпляром.

Если вы расширяете класс A как B и создаете экземпляр одного из них (оставляя все остальное одинаковым), вы получаете такое же поведение:

<?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"
?>

Еще раз, никаких сюрпризов. Давайте вернемся к первому примеру и немного подправим его. Сначала мы перемещаем вызов создания / инкремента статической переменной в метод-член. Обратите внимание, что я удалил класс B для этого:

<?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"
?>

Все тот же вывод.

Однако , когда вы расширяете A как B и оставляете ту же структуру на месте:

<?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"
?>

Обратите внимание на вывод: во всех остальных случаях $o2->i стало 2, кроме этого.

Так что, похоже, что если мы расширим A и , переместим статическое создание экземпляра в метод экземпляра, мы теперь, похоже, представили новую область видимости для переменной $i, тогда как во всех других случаях экземпляры имеют общую область видимости для этой статической переменной.

Еще более запутанно , рассмотрим этот пример; он идентичен предыдущему, но в этом случае класс B получает собственную реализацию setI(), которая просто уступает реализации своего родительского класса:

<?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"
?>

Как видите, $o2->i теперь вернулся к значению 2, что мы получили почти везде (кроме примера № 4)

Это мне кажется очень нелогичным. Я ожидаю, что или разные экземпляры получат свои собственные области действия для этой переменной, или все экземпляры (включая экземпляры расширенных классов) имеют одну и ту же область видимости.

Я не могу сказать, является ли это ошибкой в ​​PHP, или это ожидаемое поведение. Документы PHP по области действия статических переменных говорят:

Статическая переменная существует только в локальной области функций, но она не теряет своего значения, когда выполнение программы выходит из этой области.

Они не вдавались в подробности того, как определяется «область действия функции» в контексте экземпляров объекта, поэтому я не уверен, ожидается ли крайний случай в Примере № 4 или нет.

1 голос
/ 16 мая 2011

Да, будет, это также задокументировано в документации, но оно находится в разделе Область действия переменных вместо Статическое ключевое слово , что может быть причиной того, что вы его не нашли.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...