Ключевое слово static внутри функции?

110

Я искал исходники Drupal 7 и нашел кое-что, чего раньше не видел. Я сначала просмотрел руководство по php, но оно не объясняло эти примеры.

Что ключевое слово staticделает с переменной внутри функции?

function module_load_all($bootstrap = FALSE) {
    static $has_run = FALSE
user151841
источник

Ответы:

155

Это заставляет функцию запоминать значение данной переменной ( $has_runв вашем примере) между несколькими вызовами.

Вы можете использовать это для разных целей, например:

function doStuff() {
  static $cache = null;

  if ($cache === null) {
     $cache = '%heavy database stuff or something%';
  }

  // code using $cache
}

В этом примере ifбудет выполняться только один раз. Даже если doStuffпроизойдет несколько вызовов .

Йоши
источник
4
Кроме того, если функция запускалась один раз, она не сбрасывает значение $cacheв nullпри последующих вызовах, верно?
user151841 06
7
@ user151841 $cacheбудет сброшен только между запросами. Так что да, он не будет сброшен при последующих вызовах в том же запросе (или выполнении скрипта).
Йоши
14
@Muhammad, потому что это как раз то, что делают статические ключевые слова .
Йоши
2
Я считаю, что ifпроверка условий $cache === nullбудет выполняться каждый раз, когда эта функция вызывается, не думаю , что код блока $cache = '..'будет выполнен.
Айварас,
что произойдет, если функция является методом в классе, является ли статическая переменная общей между экземплярами?
Сантьяго Аризти
83

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

Учти это:

class Foo
{
    public function call()
    {
        static $test = 0;

        $test++;
        echo $test . PHP_EOL; 
    }
}

$a = new Foo();
$a->call(); // 1
$a->call(); // 2
$a->call(); // 3


$b = new Foo();
$b->call(); // 4
$b->call(); // 5

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

class Bar
{
    private $test = 0;

    public function call()
    {
        $this->test++;
        echo $this->test . PHP_EOL; 
    }
}


$a = new Bar();
$a->call(); // 1
$a->call(); // 2
$a->call(); // 3


$b = new Bar();
$b->call(); // 1
$b->call(); // 2
Ян
источник
1
Ой! Меня это не раз укусило. Я ожидал, что статика будет применяться только к экземпляру, обеспечивая мемоизацию; но это был неправильный образ мышления, потому что «статика» в контексте классов означает класс в целом. Свойства, методы, переменные И.
systemovich
14

Рассмотрим следующий пример:

function a($s){
    static $v = 10;
    echo $v;
    $v = $s;
}

Первый звонок

a(20);

выведет 10, значит $vбыть 20. Переменная$v не собирается в мусор после завершения функции, поскольку это статическая (нединамическая) переменная. Переменная останется в пределах своей области до полного завершения скрипта.

Поэтому следующий вызов

a(15);

затем будет выводиться 20, а затем будет установлено $vзначение 15.

Маурис
источник
9

Статика работает так же, как и в классе. Переменная является общей для всех экземпляров функции. В вашем конкретном примере после запуска функции $ has_run устанавливается в TRUE. Все будущие запуски функции будут иметь $ has_run = TRUE. Это особенно полезно в рекурсивных функциях (как альтернатива передаче счетчика).

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

См. Http://php.net/manual/en/language.variables.scope.php

тофутим
источник
3

статическая переменная в функции означает, что независимо от того, сколько раз вы вызываете функцию, существует только 1 переменная.

<?php

class Foo{
    protected static $test = 'Foo';
    function yourstatic(){
        static $test = 0;
        $test++;
        echo $test . "\n"; 
    }

    function bar(){
        $test = 0;
        $test++;
        echo $test . "\n";
    }
}

$f = new Foo();
$f->yourstatic(); // 1
$f->yourstatic(); // 2
$f->yourstatic(); // 3
$f->bar(); // 1
$f->bar(); // 1
$f->bar(); // 1

?>
Pwnna
источник
3

Чтобы расширить ответ Янга

Если вы расширяете класс статическими переменными, отдельные расширенные классы будут содержать свои «собственные» статические данные, на которые ссылаются, которые совместно используются между экземплярами.

<?php
class base {
     function calc() {
        static $foo = 0;
        $foo++;
        return $foo;
     }
}

class one extends base {
    function e() {
        echo "one:".$this->calc().PHP_EOL;
    }
}
class two extends base {
    function p() {
        echo "two:".$this->calc().PHP_EOL;
    }
}
$x = new one();
$y = new two();
$x_repeat = new one();

$x->e();
$y->p();
$x->e();
$x_repeat->e();
$x->e();
$x_repeat->e();
$y->p();

выходы:

один: 1
два : 1
один: 2
один : 3 <- x_repeat
one: 4
one : 5 <- x_repeat
two : 2

http://ideone.com/W4W5Qv

Tschallacka
источник
1

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

Поэтому в приведенном вами примере, если вы вызовете функцию дважды, если она установлена $has_runв значение true, тогда функция сможет узнать, что она была ранее вызвана, потому $has_runчто она все равно будет равна, trueкогда функция запускается во второй раз.

Использование staticключевого слова в этом контексте объясняется в руководстве по PHP здесь: http://php.net/manual/en/language.variables.scope.php

Spudley
источник