static 的几种使用情况:
1. 静态变量
静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。看看下面的例子:
1 |
|
如果不声明static
,则每次$val
的值都会初始化为1。这是由于static
关键字会在请求初始化时存储与静态存储区,并存在于整个请求生命周期内,而普通变量则存在于栈区,函数执行结束时这些存储单元自动被释放。
2. 静态属性
1 | class A { |
3. 静态方法
1 | class A { |
4. 后期静态绑定
首先,后期静态绑定这个词怎么理解,官方手册对这个解释的很清楚,这里引用一下:『“后期绑定”的意思是说,static::
不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为“静态绑定”,因为它可以用于(但不限于)静态方法的调用』。也就是说,static 的值只有在调用时才能确定下来,而 self 则是在定义时就确定下来的。
接下来,让我们用几个例子来具体说明一下:
1 |
|
这段代码的最终输出是什么?A
还是B
?
让我们来运行一下,发现结果是B
。这是为什么呢?
因为当我们调用B
中的静态方法test()
时,B 中不存在,于是向上查找(调用查找顺序依次为 当前类 ==> trait ==> 父类),当在父类A
中找到时,执行static::who()
。(这里的static
与我们常用的self
关键字不同,如果是self
,则只会向上查找,而static
则会向下查找,具体调用方法也是在运行时确定的)因此接下来调用的是B
中的 who()
,而非A
中的who()
,最终也就自然输出为B
。
需要注意的是,后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止(即最下层可执行的方法)。另一方面,如果静态调用使用 parent::
或者 self::
将转发调用信息。
1 |
|
What & When
现在,让我们来看一下什么是static
,以及什么时候该使用static
。
什么是static?
如果我们在代码中声明了static
关键字,代码在初始化阶段会与常量、全局变量一同存储在一段连续空间内(静态存储区),这会存在于整个请求周期,除非我们手动销毁。
由于这些值是在初始化时确定的,相比于在运行时确定的值,就是“静态”(static
)的。
什么时候用?
由于是一段连续的空间,相比于运行时的碎片化产生的内容读取效率更高,所以,我们应将一些常用基础工具类设为静态,既避免了实例化时的资源消耗,有提升了书写体验。但要注意不能滥用static
,曾经的一家知名公司内部项目model层全部是static
方法,你能想象到这维护起来有多么让人崩溃。