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