php 单例模式
进行单例模式之前来一个热身
function test()
{
static $nm = 2;
$nm = $nm * $nm;
print $nm."
";
}
// 第一次执行,$nm = 4
test();
// 第一次执行,$nm = 16
test();
// 第一次执行,$nm = 256
test();
静态变量只存在于函数作用域内,也就是说,静态变量只存活在栈中。一般的函数内变量在函数结束后会释放,比如局部变量,但是静态变量却不会。就是说,下次再调用这个函数的时候,该变量的值会保留下来。
单例类需要注意以下几点:
1、构造函数需要标记为private(访问控制:防止外部代码使用new操作符创建对象),单例类不能在其他类中实例化,只能被其自身实例化;
2、拥有一个保存类的实例的静态成员变量,下次访问 该变量的值会保留下来。
3、拥有一个访问这个实例的公共的静态方法(常用getInstance()方法进行实例化单例类,通过instanceof操作符可以检测到类是否已经被实例化)
4、需要创建__clone()方法防止对象被复制(克隆)
为什么要使用PHP单例模式?
1、php的应用主要在于数据库应用, 所以一个应用中会存在大量的数据库操作, 使用单例模式, 则可以避免大量的new 操作消耗的资源。
2、如果系统中需要有一个类来全局控制某些配置信息, 那么使用单例模式可以很方便的实现. 这个可以参看ZF的FrontController部分。
3、在一次页面请求中, 便于进行调试, 因为所有的代码(例如数据库操作类db)都集中在一个类中, 我们可以在类中设置钩子, 输出日志,从而避免到处var_dump, echo。
代码实现:
<?php
function test()
{
static $nm = 2;
$nm = $nm * $nm;
print $nm."<br />";
}
// 第一次执行,$nm = 4
test();
// 第一次执行,$nm = 16
test();
// 第一次执行,$nm = 256
test();
Class Db{
public $_dbname;
private static $_instance;
private function __construct(){
echo 'This is a Constructed method;';
}
public static function getInstance(){
if(self::$_instance === null){
self::$_instance = new self();
}
return self::$_instance;
}
private function __clone(){
echo 'this is clone Object';
trigger_error('Clone is not allow!',E_USER_ERROR);
}
public function getDbName(){
echo $this->_dbname;
}
public function setDbName($dbname){
$this->_dbname=$dbname;
}
public function ceshi(){
return 2323;
}
}
$instance = Db::getInstance();
// $instance1 = Db::getInstance();
// 克隆对象
$db_clone = clone $instance;
// if($db_clone === $instance){
// echo '相等';
// }
// echo $db_clone->ceshi();
// echo '不相等';
// die;
// echo $instance1->ceshi();
// echo $instance2->ceshi();
// if($instance1 === $instance2){
// echo '相等';die;
// }
// echo '不相等';die;
单例模式防止被克隆有两种方式:
1、:设置魔术方法__clone();访问权限为private
private function __clone(){
echo 'this is clone Object';
trigger_error('Clone is not allow!',E_USER_ERROR);
}
2、若__clone()为公用方法,则在函数中加上自定义错误,如trigger_error('Clone is not allow!',E_USER_ERROR);
public function __clone(){
trigger_error('Clone is not allow!',E_USER_ERROR);
}