在类成员定义的前面加上static关键字,此成员就被定义为静态成员,静态成员的特点是它属性于类,而不是某个对象。所以,我们也称静态成员为类成员,而相对应的,非静态成员则称为实例成员。
先看一个简单的示例。
在这个CTest类中,我们定义了静态变量num转换成十六进制字符串,而strtoupper()函数则是将字符串中的字母转换为大写形式。
请注意静态成员的访问形式:
- 在类的内部,如getHex()函数中,我们使用self关键字表示所属的类,访问静态成员时使用“self::<成员>”的格式,请注意其中是两个冒号;如果我们在类的内部使用getHex()函数,则应该使用“self::getHex()”语句。
- 在类的外部访问类的静态成员时,使用“<类名>::<成员>”的格式,如代码中的“CTest::$num”和“CTest::getHex()”语句。
如果把静态成员当成实例成员使用,就会产生错误,如下面的代码就是错误的。
此外,还有一点需要注意,在PHP中,静态和实例成员都不能同名。
单件模式
静态成员的主题就是“唯一”。无论创建多少类的实例,类的静态成员都是唯一的,根据这一特点,在开发中,我们可以将需要统一管理的资源定义为只能创建一个实例,而典型的应用就是设计模式中的“单件模式(Singleton Pattern)”。先看下面的代码。
先看CSingleton类的定义,实现单件的关键在于:
- $singleton对象,即单件对象,它定义为私有静态成员,我们只能通过getInstance()方法来获取这个对象。
- getInstance()方法,获取CSingleton类唯一实例的方法,同样被定义为静态成员;在这个方法中,如果$singleton对象为null则创建它,然后,返回这个对象
- 构造函数和__clone()方法,它们都被定义为私有的,这样一来,你无法使用new关键创建CSingleton类的对象,也无法使用clone关键字复制一个新的对象。这样就进一步保证了$singleton对象是唯一的实例。
- 最后是getId()方法,它是一实例方法,用于给出ID值,每次都会加一。请注意它的实现,我们使用了前加1运算,如果使用后加1,则相同功能的代码应该是:
再看单件的使用,我们得到一个CSingleton类的实例的唯一办法就是通过getInstance()方法;代码中,我们使用两个对象obj2分别获取CSingleton实例,但从运行的结果中,大家可以看到,显示的内容是从1到20的数值,也就是说,obj2对象实际上都是在引用CSingleton类中的$singleton对象,而不是在独立地工作。这就是一个基本的单件模式地应用,在项目中,单件的功能就是对唯一的资源进行统一的管理,避免资源出现分配混乱的问题。
__callStatic()方法
前面,我们讨论的__call()方法用于自动调用对象中没有定义过的实例方法,而对于类中没有定义的静态方法的自动调用,我们则需要使用__callStatic()方法。如下面的代码。
__callStatic()方法必须被定义为静态(static)成员,而其它的应用方法则与__call()方法比较相似了,大家可以参考__call()多做测试以加深映像。