设计模式 - 关于PHP单例模式,有一点不明白,求指教!

 为谁落慕 发布于 2022-11-20 15:03

首先,我定义个类,实现单例模式:(这里是简单一写,就是个最基本的单例)

class Demo
{
    public static $instance;
    
    private function __Construct()
    {
        //TODO
    }
    
    public static function getInstance()
    {
        if(!self::$instance){
            self::$instance = new static();
        }
        
        return self::$instance;
    }
    
    public function call()
    {
        //其他方法
    }
}

下面有两种方式实例化类:

1.在需要用的地方

$aa = Demo::getInstance();
$bb = Demo::getInstance();
$cc = Demo::getInstance();

这样调用肯定是没问题的,一般情况也是这样初始化。

2.定义一个普通类,写个函数初始化,保存在一个静态变量,如下:

类:

class Demo{
    public function __Construct(){
        //TODO
    }
}

函数:

function get_obj(){
    static $obj;
    if($obj){
        return $obj;
    }else{
        $obj = new Demo;
        return $obj;
    }
}

在需要调用的地方这样写:

$obj = get_obj();
$obj->call();

$obj2 = get_obj();
$obj2->call();

$obj3 = get_obj();
$obj3 = get_obj();

这样不是也只实例化一次这个类吗?

13 个回答
  • 单例的要义第一:私有化构造方法,当然PHP还提供了clone魔术方法,也要私有化。这样做事为了保证外部实例化对象的入口只有一个,只能是我们暴露出来的静态函数getInstance()

    2022-11-20 18:54 回答
  • get_obj()那种写法无法保证外部不new Demo对象

    2022-11-20 18:54 回答
  • 单例首先是面向对象里面的概念,
    第二种就不是面向对象

    2022-11-20 18:54 回答
  • 单例模式,是一种设计思想实现方式

    2022-11-20 18:54 回答
  • 你那样写不符合面向对象思想的,而且你的单例模式也不完整,没有考虑到clone和extends的情况。可以参考下http://www.xtwind.com/design-pattern-singleton.html

    2022-11-20 18:54 回答
  • 第二种方式是单例吗?

    class Demo {
        public function __construct(){
            //TODO
        }
    }
    function get_obj() {
        static $obj;
        if($obj){
            return $obj;
        }else{
            $obj = new Demo;
            return $obj;
        }
    }
    
    var_dump(get_obj());
    var_dump(new Demo);
    

    得出的是2个不同的实例

    2022-11-20 18:54 回答
  • $instance = new static(); (楼主这行代码写错了),感觉单例模式就是个思想,你第一个例子就是面向对象,第二个例子既有面向对象,又有面向过程。

    单例模式是指整个应用中类只有一个对象实例的设计模式。

    2022-11-20 18:54 回答
  • 楼主给了我启发,过程式编程中,在全局函数内用静态变量存储数据库连接实现单例:

    <?php
    // config.php
    $app = array(
        'db_host'        => '127.0.0.1',
        'db_username'    => 'root',
        'db_password'    => '',
        'db_name'        => 'mysql'
    );
    // functions.php
    function cn_db() {
        global $app;
        static $mysqli;
        if ($mysqli) {
            return $mysqli;
        } else {
            $mysqli = new mysqli($app['db_host'], $app['db_username'], $app['db_password'], $app['db_name']);
            return $mysqli;
        }
    }
    function cn_foo1() {
        $mysqli = cn_db();
        return $mysqli->query('select user,host from user where user = \'root\'')->fetch_all();
    }
    function cn_foo2() {
        $mysqli = cn_db();
        return $mysqli->query('select user,host from user')->fetch_all();
    }
    // controller + view
    print_r(cn_foo1());
    print_r(cn_foo2());
    2022-11-20 18:54 回答
  • 静态变量可以定义在函数里或者类属性,两种写法都可以,但前者封装性会比较好些。

    2022-11-20 18:54 回答
  • = = 所以呢?
    两种写法而已啊。。。
    另外,你无论怎么看,都还是第一种更清晰,更独立,更好用啊。。。
    第一种封装、抽象的更好,更加符合面向对象啊。
    存一个静态变量或者另外弄个函数什么的,你不觉得乱嘛。。。

    2022-11-20 18:54 回答
  • 单例模式,三私一公,其中的三私:构造方法,克隆魔术方法,实例化对象。一公:对外提供的方法

    2022-11-20 18:54 回答
  • 这问题我也有印象,我也答过一次
    http://segmentfault.com/q/1010000003894638
    看了一下还是题主你,为毛要问两遍……

    然后你的第二种方式并非单例,请不要陷入抠概念的误区
    偶尔也有你这种用法的,少见,并且不好。在一般情况下用一个特定对象就行了,特殊情况下需要新的实例的场合会用,但一般也不会这么写(早期的PHP会有一些类这么做)

    2022-11-20 18:54 回答
  • 完善的单例应该是这样的

    class Foobar {
        static private $instance;
        
        // 禁止外部new Foobar
        private function __construct() {
        }
        
        // 禁止clone $foobar
        private function __clone() {
        }
        
        static public function getInstance() {
            retrun self::$instance
                ?: (self::$instance = new self);
        }
    }

    如果还要考虑到继承的话

    class Foo {
        static private $instances = [];
    
        protected function __construct() {
        }
    
        final private function __clone() {
        }
    
        final static public function getInstance() {
            $class = get_called_class();
    
            if (!isset(self::$instances[$class])) {
                self::$instances[$class] = new static;
            }
    
            return self::$instances[$class];
        }
    }
    
    class Bar extends Foo {
    
    }
    
    $foo = Foo::getInstance();
    $bar = Bar::getInstance();

    get_obj()那种写法,也可以达到目的,但无法禁止new和clone,也就无法做到真正的单例

    2022-11-20 18:54 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有