函数内的 `static` 关键字是什么意思?

135
我在查看Drupal 7的源代码时发现了一些我之前从未见过的东西。我在php手册中进行了一些初步查找,但它没有解释这些示例。
关于函数内的变量,关键字“静态(static)”有什么作用?
function module_load_all($bootstrap = FALSE) {
    static $has_run = FALSE

9
好的,以下是翻译的内容:PHP 变量作用域变量的作用域是指在脚本中可以访问该变量的位置。PHP 变量的作用域分为三种不同的类型:局部变量、全局变量和静态变量。在函数或类的方法内声明的变量是局部变量,它们只能在函数内或该方法内访问。如果要在函数或方法之外访问变量,则必须将其声明为全局变量或使用超全局变量。全局变量可以在函数内或方法内进行访问。要在函数或方法中使用全局变量,需要使用 global 关键字将其引入。静态变量仅在首次访问时进行初始化,并且在函数执行完后仍然保留其值。在函数或类的方法中声明静态变量使用 static 关键字。示例代码: - Mahesh
这可能是我最喜欢的 PHP 特性! - Robert Moskal
7个回答

196

这使得函数可以在多次调用之间记住给定变量的值 ($has_run 是您示例中的变量)。

您可以将其用于不同的目的,例如:

function doStuff() {
  static $cache = null;

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

  // code using $cache
}
在这个示例中,if语句只会执行一次。即使有多次调用doStuff

6
如果这个函数已经运行过一次,那么后续的调用中 $cache 的值不会被重置为 null,对吗? - user151841
7
$cache 只会在请求之间被重置。因此,在同一请求(或脚本的执行)中后续调用时,它将 不会被重置 - Yoshi
14
@Muhammad,因为这就是关键字 static 的作用。 - Yoshi
3
我认为每次调用此函数时,都会执行 if 条件检查 $cache === null,尽管不一定会执行 if 代码块中的 $cache = '..'。请注意,我的翻译并没有改变原文的含义,只是使其更通俗易懂。 - Aivaras
1
如果函数是类中的方法,那么静态变量在实例之间是否共享? - santiago arizti
显示剩余4条评论

108

目前似乎没有人提到,在同一类的不同实例中的静态变量保留它们的状态。因此,在编写面向对象的代码时要小心。

考虑以下内容:

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

2
哎呀!这个问题已经咬了我不止一次。我原本以为静态只适用于实例,提供记忆化;但这种想法是错误的,因为在类的上下文中,“静态”意味着整个类。包括属性、方法和变量。 - Geoffrey

15

给定以下示例:

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

首次调用

a(20);

将输出10,然后变量$v的值为20。变量$v是一个静态(非动态)变量,在函数结束后不会被垃圾回收。该变量将一直存在于其作用域中,直到脚本完全结束。

因此,下面的调用结果为:

a(15);

接着会输出20,然后将$v设为15


11

静态变量在函数中的使用方式与类中相同。该变量在函数的所有实例之间共享。 在您的特定示例中,运行函数后,$has_run被设置为TRUE。 函数的所有未来运行都将具有$has_run = TRUE。 这在递归函数中特别有用(作为传递计数的替代方法)。

静态变量仅存在于本地函数作用域中,但程序执行离开此作用域时,它不会失去其值。

参见http://php.net/manual/en/language.variables.scope.php


6

进一步解释Yang的答案

如果您通过静态变量扩展一个类,则各个扩展类将拥有自己的引用静态变量,这些变量在实例之间共享。

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

输出:

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

http://ideone.com/W4W5Qv


3

函数中的静态变量表示无论你调用函数多少次,都只有一个变量。

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

?>

2
在一个函数内部,static 表示变量在页面加载的生命周期内,每次调用函数时都会保留其值。
因此,在你给出的例子中,如果你调用了两次函数,并且将 $has_run 设置为 true,那么函数就能知道它之前已经被调用过,因为当函数第二次开始时,$has_run 仍然等于 true
在这种情况下使用 static 关键字的用法在 PHP 手册中有解释: http://php.net/manual/en/language.variables.scope.php

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接