请考虑以下内容:
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。或更笼统地说,它们如何在内部正常工作?
答案 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
的相同实例。
不幸的是,我在文档中找不到一个很好的简单摘要,而且我也不知道有多少是设计使然的。我认为我从来没有遇到过构造函数中的静态变量,而且静态函数变量本身也越来越少见。但是知道事情是如何运作的,这是一个很好的问题,很有趣。