Từ khóa `static` bên trong hàm?


110

Tôi đang xem mã nguồn của Drupal 7 và tôi đã tìm thấy một số thứ mà tôi chưa từng thấy trước đây. Tôi đã tìm kiếm ban đầu trong hướng dẫn sử dụng php, nhưng nó không giải thích những ví dụ này.

Từ khóa staticlàm gì với một biến bên trong một hàm?

function module_load_all($bootstrap = FALSE) {
    static $has_run = FALSE

Câu trả lời:


155

Nó làm cho hàm nhớ giá trị của biến đã cho ( $has_runtrong ví dụ của bạn) giữa nhiều lần gọi.

Bạn có thể sử dụng nó cho các mục đích khác nhau, ví dụ:

function doStuff() {
  static $cache = null;

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

  // code using $cache
}

Trong ví dụ này, lệnh ifsẽ chỉ được thực thi một lần. Ngay cả khi nhiều cuộc gọi đến doStuffsẽ xảy ra.


4
Ngoài ra, nếu các chức năng đã chạy một lần, nó sẽ không thiết lập lại giá trị của $cacheđể nullcho các cuộc gọi sau đó, phải không?
user151841

7
@ user151841 $cachesẽ chỉ được đặt lại giữa các yêu cầu. Vì vậy, có, nó sẽ không được đặt lại trên các cuộc gọi trễ trong cùng một yêu cầu (hoặc thực thi tập lệnh).
Yoshi

14
@Muhammad vì đó chỉ là những gì các từ khóa tĩnh làm.
Yoshi

2
Tôi tin rằng ifkiểm tra điều kiện $cache === nullsẽ được thực hiện mỗi khi hàm này được gọi, không nghĩ là nếu mã khối của $cache = '..'sẽ được thực thi.
Aivaras

điều gì sẽ xảy ra nếu hàm là một phương thức trong một lớp, biến tĩnh có được chia sẻ giữa các trường hợp không?
santiago arizti

83

Có vẻ như không ai đề cập đến cho đến nay, rằng các biến tĩnh bên trong các thể hiện khác nhau của cùng một lớp vẫn giữ nguyên trạng thái của chúng. Vì vậy, hãy cẩn thận khi viết mã OOP.

Xem xét điều này:

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

Nếu bạn muốn một biến static chỉ nhớ trạng thái của nó đối với cá thể lớp hiện tại, bạn nên gắn vào một thuộc tính lớp, như sau:

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
Ôi chao! Điều này đã cắn tôi nhiều hơn một lần. Tôi mong đợi static chỉ áp dụng cho phiên bản, cung cấp khả năng ghi nhớ; nhưng đó là cách suy nghĩ sai lầm, bởi vì "tĩnh" trong ngữ cảnh của các lớp có nghĩa là cho cả lớp. Thuộc tính, phương thức, biến AND.
systemovich

14

Cho ví dụ sau:

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

Cuộc gọi đầu tiên của

a(20);

sẽ xuất 10, sau đó $v20. Biến $vkhông được thu thập rác sau khi hàm kết thúc, vì nó là một biến tĩnh (không động). Biến sẽ ở trong phạm vi của nó cho đến khi tập lệnh kết thúc hoàn toàn.

Do đó, cuộc gọi sau của

a(15);

sau đó sẽ ra 20, và sau đó thiết lập $vđược 15.


9

Static hoạt động giống như cách nó làm trong một lớp. Biến được chia sẻ trên tất cả các phiên bản của một hàm. Trong ví dụ cụ thể của bạn, khi hàm được chạy, $ has_run được đặt thành TRUE. Tất cả các lần chạy hàm trong tương lai sẽ có $ has_run = TRUE. Điều này đặc biệt hữu ích trong các hàm đệ quy (thay thế cho việc chuyển số đếm).

Biến static chỉ tồn tại trong phạm vi hàm cục bộ, nhưng nó không mất giá trị khi việc thực thi chương trình rời khỏi phạm vi này.

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


3

Biến static trong một hàm có nghĩa là dù bạn có gọi hàm bao nhiêu lần thì cũng chỉ có 1 biến duy nhất.

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

?>

3

Để mở rộng câu trả lời của Yang

Nếu bạn mở rộng một lớp với các biến tĩnh, các lớp mở rộng riêng lẻ sẽ giữ tĩnh tham chiếu "riêng" của chúng được chia sẻ giữa các phiên bản.

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

kết quả đầu ra:

một: 1
hai : 1
một: 2
một : 3 <- x_repeat
một: 4
một : 5 <- x_repeat
hai : 2

http://ideone.com/W4W5Qv


1

Bên trong một hàm, staticcó nghĩa là biến sẽ giữ nguyên giá trị của nó mỗi khi hàm được gọi trong thời gian tải trang.

Do đó, trong ví dụ bạn đã đưa ra, nếu bạn gọi một hàm hai lần, nếu nó được đặt $has_runthành true, thì hàm sẽ có thể biết rằng nó đã được gọi trước đó vì $has_runvẫn sẽ bằng truekhi hàm bắt đầu lần thứ hai.

Cách sử dụng statictừ khóa trong ngữ cảnh này được giải thích trong hướng dẫn sử dụng PHP tại đây: http://php.net/manual/en/language.variables.scope.php

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.