słowo kluczowe `static` wewnątrz funkcji?

110

Szukałem źródła Drupala 7 i znalazłem kilka rzeczy, których wcześniej nie widziałem. Najpierw zajrzałem do podręcznika php, ale nie wyjaśniłem tych przykładów.

Co robi słowo kluczowe staticze zmienną wewnątrz funkcji?

function module_load_all($bootstrap = FALSE) {
    static $has_run = FALSE
user151841
źródło

Odpowiedzi:

155

Sprawia, że ​​funkcja zapamiętuje wartość danej zmiennej ( $has_runw naszym przykładzie) między wieloma wywołaniami.

Możesz użyć tego do różnych celów, na przykład:

function doStuff() {
  static $cache = null;

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

  // code using $cache
}

W tym przykładzie ifoperacja zostanie wykonana tylko raz. Nawet jeśli doStuffwystąpiłoby wiele wywołań .

Yoshi
źródło
4
Ponadto, jeśli funkcja została uruchomiona raz, nie zresetuje wartości $cachedo nullprzy późniejszych wywołaniach, prawda?
user151841
7
@ user151841 $cachezostanie zresetowany tylko między żądaniami. Więc tak, nie będzie resetowany przy późniejszych wywołaniach w tym samym żądaniu (lub wykonaniu skryptu).
Yoshi,
14
@Muhammad, ponieważ to właśnie robią słowa kluczowe static .
Yoshi
2
Uważam, że ifsprawdzanie warunku $cache === nullbyłoby wykonywane za każdym razem, gdy wywoływana jest ta funkcja, a nie, gdyby kod blokowy $cache = '..'został wykonany.
Aivaras
co się stanie, jeśli funkcja jest metodą w klasie, czy zmienna statyczna jest dzielona między instancjami?
santiago arizti
83

Wygląda na to, że nikt do tej pory nie wspomniał, że zmienne statyczne w różnych instancjach tej samej klasy pozostają w ich stanie. Dlatego zachowaj ostrożność podczas pisania kodu OOP.

Rozważ to:

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

Jeśli chcesz, aby zmienna statyczna pamiętała swój stan tylko dla bieżącej instancji klasy, lepiej trzymaj się właściwości klasy, takiej jak ta:

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
Yang
źródło
1
Auć! To ugryzło mnie nie raz. Spodziewałem się, że statystyka będzie miała zastosowanie tylko do instancji, zapewniając zapamiętywanie; ale to był zły sposób myślenia, ponieważ „statyczny” w kontekście klas oznacza dla klasy jako całości. Właściwości, metody i zmienne AND.
systemovich
14

Biorąc pod uwagę następujący przykład:

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

Pierwsze połączenie

a(20);

wyjdzie 10, a następnie $vbędzie 20. Zmienna $vnie jest usuwana z pamięci po zakończeniu funkcji, ponieważ jest zmienną statyczną (niedynamiczną). Zmienna pozostanie w swoim zakresie do całkowitego zakończenia działania skryptu.

Dlatego następujące wywołanie

a(15);

wyświetli wynik 20, a następnie zostanie ustawiony $vna 15.

Mauris
źródło
9

Statyczny działa tak samo, jak w klasie. Zmienna jest wspólna dla wszystkich instancji funkcji. W Twoim przykładzie po uruchomieniu funkcji $ has_run jest ustawiana na TRUE. Wszystkie przyszłe uruchomienia funkcji będą miały $ has_run = TRUE. Jest to szczególnie przydatne w funkcjach rekurencyjnych (jako alternatywa dla przekazywania liczby).

Zmienna statyczna istnieje tylko w zakresie funkcji lokalnej, ale nie traci swojej wartości, gdy wykonywanie programu opuszcza ten zakres.

Zobacz http://php.net/manual/en/language.variables.scope.php

tofutim
źródło
3

zmienna statyczna w funkcji oznacza, że ​​bez względu na to, ile razy wywołujesz funkcję, jest tylko jedna zmienna.

<?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
źródło
3

Aby rozwinąć odpowiedź Yang

Jeśli rozszerzysz klasę o zmienne statyczne, poszczególne klasy rozszerzone będą posiadać własne, do których odwołuje się statystyka, które są współdzielone między instancjami.

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

wyjścia:

one: 1
two : 1
one: 2
one : 3 <- x_repeat
one: 4
one : 5 <- x_repeat
two : 2

http://ideone.com/W4W5Qv

Tschallacka
źródło
1

Wewnątrz funkcji staticoznacza, że ​​zmienna zachowa swoją wartość za każdym razem, gdy funkcja zostanie wywołana w trakcie ładowania strony.

Dlatego w podanym przykładzie, jeśli wywołasz funkcję dwukrotnie, jeśli jest ustawiona $has_runna true, wówczas funkcja będzie mogła wiedzieć, że została wcześniej wywołana, ponieważ $has_runnadal będzie równa temu, truegdy funkcja zostanie uruchomiona po raz drugi.

Użycie staticsłowa kluczowego w tym kontekście jest wyjaśnione w podręczniku PHP tutaj: http://php.net/manual/en/language.variables.scope.php

Spudley
źródło