静态函数变量与静态类变量

时间:2018-08-21 09:48:43

标签: php oop php-7.2

请考虑以下内容:

class Super
{
    static protected $class_var = 0;

    public function __construct()
    {
        static $function_var = 0;

        static::$class_var++;
        $function_var++;

        echo sprintf("class_name : %s, class_var : %s, function_var : %s\n", static::class, static::$class_var, $function_var);
    }

    public static function test()
    {
        static $function_var = 0;

        static::$class_var++;
        $function_var++;

        echo sprintf("class_name : %s, class_var : %s, function_var : %s\n", static::class, static::$class_var, $function_var);
    }
}

class A extends Super {}
class B extends Super {}

echo "Object calls\n";
new A();
new A();
new B();
echo "Class calls\n";
A::test();
A::test();
B::test();

PHP 7.2.7输出:

Object calls
class_name : A, class_var : 1, function_var : 1
class_name : A, class_var : 2, function_var : 2
class_name : B, class_var : 3, function_var : 3
Class calls
class_name : A, class_var : 4, function_var : 1
class_name : A, class_var : 5, function_var : 2
class_name : B, class_var : 6, function_var : 1

为什么在类上调用A和B具有自己的静态函数var。而A和B在实例上调用时共享静态函数var。或更笼统地说,它们如何在内部正常工作?

1 个答案:

答案 0 :(得分:2)

可以这样解释一般行为(以下关于构造函数的附加条件):静态类属性的作用域是定义的类,而静态方法变量的作用域是针对该类的因此,它们被称为

您的test方法被声明为静态的事实在这里并不重要,因此我将其简化为以下测试脚本:

class Super
{
    static protected $class_var = 0;

    public function test()
    {
        static $function_var = 0;

        static::$class_var++;
        $function_var++;

        echo sprintf("class_name : %s, class_var : %s, function_var : %s", static::class, static::$class_var, $function_var), PHP_EOL;
    }
}

class A extends Super {}
class B extends Super {}

因为它是在类中定义的,所以$class_var将始终链接到该作用域。但是,许多类都扩展了Super,它们将引用相同的变量(除非它们覆盖了该变量)。

另一方面,

$function_var的范围是test方法称为 的类。调用A的所有实例将共享一个,调用B的所有实例将共享一个。

$a = new A;
$b = new B;

$a->test(); // class_name : A, class_var : 1, function_var : 1
$a->test(); // class_name : A, class_var : 2, function_var : 2
$b->test(); // class_name : B, class_var : 3, function_var : 1

构造函数(条件):

问题中的另一个问题是,构造函数的行为不同于任何其他类方法,因为尽管语法上相似,但它根本不是一个方法。与类属性类似,在构造函数中声明为static的任何变量的作用域为定义的类:

如果我们添加:

public function __construct()
{
    static $constructor_var = 0;
    $constructor_var++;

    echo sprintf("class_name : %s, constructor_var : %s", static::class, $constructor_var), PHP_EOL;
}

然后我们可以演示如下:

$a = new A; // class_name : A, constructor_var : 1
$b = new B; // class_name : B, constructor_var : 2

除非所有子类都重写构造函数,否则它们都将共享$constructor_var的相同实例。

不幸的是,我在文档中找不到一个很好的简单摘要,而且我也不知道有多少是设计使然的。我认为我从来没有遇到过构造函数中的静态变量,而且静态函数变量本身也越来越少见。但是知道事情是如何运作的,这是一个很好的问题,很有趣。