单例模式

单例模式(也叫单件模式)是让一个类在内存中仅有一个实例。(也就是类的访问,不实例化对象new)

单例模式的优势

单例模式保证在整个应用程序的声明周期中,任何一个时刻,单例类的实例都只存在一个,从而更加高效地利用系统资源。

技术点要求

  • 不能用new类名的方式来创建一个对象;
  • 禁止类的构造方法被重写;
  • 禁止类的实例被外界克隆;
<?php

class Db{
    public function __construct()
    {
        echo "有新的Db类的对象创建了<br/>";
    }
}
$db1=new Db();//在PHP面向对象二 说道new 个对象就代表在内存中分配个地址
$db2=new Db();

那么我们把构造函数私有化(private)这样的话,因为是私有属性外部无法访问,也就阻止了实例化。

实现技术点1

<?php

class Db{
    public static $db;//保存类的唯一实例对象
    private function __construct()
    {
        echo "有新的Db类的对象创建了<br/>";
    }

    static function getDb(){
        if(self::$db==null && !(self::$db instanceof self)){
            //self::$db instanceof self 这句话的意思就是如果 $db 是不是这个类的本身
            self::$db=new self();
        }
       return self::$db;
    }
}
Db::getDb();
Db::getDb();

以上要注意的点

<?php

class Db{
    private  static $db; //保存类的唯一实例对象
    // public static $db;  public 修饰符不推荐使用
    private function __construct()
    {
        echo "有新的Db类的对象创建了<br/>";
    }

    static function getDb(){
        if(self::$db==null && !(self::$db instanceof self) ){
            //self::$db instanceof self 这句话的意思就是如果 $db 是不是这个类的本身
            self::$db=new self();
        }
        return self::$db;
    }
    public function test(){
        echo "我是test方法<br/>";
    }
}
Db::getDb();
Db::getDb();
$db=Db::getDb();
//如果上面的getDb方法不判断这个对象是否是类的本身会出现一个漏洞  这是修饰符是public 的情况下
//最好 是  修饰符为 private
//测试  && !(self::$db instanceof self)  去掉  Db::$db = 111; 在外边赋值 会出现错误

$db->test();
//当然 现在 也有缺陷
class myDb extends Db{
    public  function __construct()
    {
        echo "myDb类有新对象创建<br/>";
    }

    public function test1(){
        echo "我是子类中的test1方法";
    }
}
$myDb= new MyDb(); //单例的类被继承重写了 单例模式的类不完全

被继承的类(还能被new)就不是单类了,怎么解决重写? 加关键字final

class Db{
    private  static $db; //保存类的唯一实例对象
    //加上关键字final 修饰  禁止重写
    final private function __construct()
    {
        echo "有新的Db类的对象创建了<br/>";
    }
}

第二条技术点解决。

这样被修饰在继承扩展也只能在扩展类声明静态的方法。

因为用的时候myDb并没有实例化、虽然子类重写但并不能实例化、而单例模式是只实例化一个对象。
链式操作是对象操作,所以扩展的子类只能是用静态方法扩展。

技术点3

<?php

class Db{
    private  static $db; //保存类的唯一实例对象
    // public static $db;  public 修饰符不推荐使用
    final private function __construct()
    {
        echo "有新的Db类的对象创建了<br/>";
    }

    static function getDb(){
        if(self::$db==null && !(self::$db instanceof self) ){
            //self::$db instanceof self 这句话的意思就是如果 $db 是不是这个类的本身
            self::$db=new self();
        }
        return self::$db;
    }
    public function test(){
        echo "我是test方法<br/>";
    }
}
$db=Db::getDb();
$db1= clone $db;

if($db1==$db){
    echo "克隆出的对象属性和方法一致<br/>";
}
if($db1===$db){
    echo "是一个对象";
}else{
    echo "不是一个对象";
}

结果这个类被克隆出来了、并不符合单例模式的设计。

解决方法就是在类的内部声明__clone()魔术方法设置私有(private)这样外部访问克隆,直接报错。

__clone()魔术方法是当对象被克隆是自动调用的方法

<?php

class Db{
    private  static $db; //保存类的唯一实例对象
    // public static $db;  public 修饰符不推荐使用
    final private function __construct()
    {
        echo "有新的Db类的对象创建了<br/>";
    }

    static function getDb(){
        if(self::$db==null && !(self::$db instanceof self) ){
            //self::$db instanceof self 这句话的意思就是如果 $db 是不是这个类的本身
            self::$db=new self();
        }
        return self::$db;
    }
    public function test(){
        echo "我是test方法<br/>";
    }
    
//    public function __clone(){
//        echo "我被克隆了<br/>";
//    }
    private function __clone(){
        echo "克隆会出错的<br/>";
    }
}
$db=Db::getDb();
$db1= clone $db;

if($db1==$db){
    echo "克隆出的对象属性和方法一致<br/>";
}
if($db1===$db){
    echo "是一个对象";
}else{
    echo "不是一个对象";
}

扩展个Db类

<?php

class Db{
    private  $link;
    private static $db;
    protected static $sql=[
        
    ];
    private function __construct($host,$uname,$upass,$Dbname)
    {
        $link=mysqli_connect($host,$uname,$upass,$Dbname) or die('数据厍连接失败');
        mysqli_set_charset($link,'utf-8');
        mysqli_select_db($link,$Dbname);
        $this->link=$link;
        return $this;
    }
    public static function configDb($host,$uname,$upass,$Dbname){
        if(self::$db==null && !(self::$db instanceof self) ){
            self::$db=new self($host,$uname,$upass,$Dbname);
        }
        return self::$db;
    }
    public static function name($name){
        self::$sql['name']=$name;
        return self::$db;
    }

    public function order($order='desc')
    {
       self::$sql['order']=$order;
        return self::$db;
    }
    function find(){
        $sqlArr=self::$sql;
        $sql="select * from {$sqlArr['name']} limit 1";
        $resArr=null;
        $res=mysqli_query($this->link,$sql);
            if(mysqli_num_rows($res)>0){
                $resArr=mysqli_fetch_assoc($res);
            }
        return $resArr;
    }
    function select()
    {
        $sqlArr=self::$sql;
        $sql="select * from {$sqlArr['name']} order by b_id  ASC";
        $resArr=[];
        $res=mysqli_query($this->link,$sql);
        if(mysqli_num_rows($res)>0){
            while ($arr=mysqli_fetch_assoc($res)){
                array_push($resArr,$arr);
            }
        }
        return $resArr;
    }

}
Db::configDb('127.0.0.1','root',123456,'dongli');
$res=Db::name('k_about')->find();
var_dump($res);
$res=Db::name('k_banner')->find();
var_dump($res);
$res=Db::name('k_banner')->order()->select();
var_dump($res);
Last modification:January 6, 2020
如果觉得我的文章对你有用,请随意赞赏