PHP的单例模式有什么用?跟直接用类本身有什么区别呢?

PHP的单例模式是为了避免重复创建对象带来的资源消耗,那么跟直接用类名::静态成员变量 ,类名::静态成员属性有什么区别呢?
另外,php是以页面为执行为执行单位的,执行完一个页面后该页面就从内存里被销毁,那么如何在不借助数据库的前提下,保存一个生存期等于整合程序执行期的变量呢?

阅读 6.5k
7 个回答

单例模式可以确保这个类在全局只能有一个实例,因为它的实例是由自己保存,在类的外部也无法对该类进行实例化。而题主所说的其他方法都不容易达到这个目的。

第二个问题说php是以页面为执行单位的,我理解意思应该是以请求为执行单位的吧?每次请求过来,php解释器会解释源代码而后执行,如果需要保存这种跨请求的变量,可以使用session保存起来,对于类实例这样的变量,也可以先序列化再保存到session中,下次请求只需要反序列化就可以了。

说下我的理解

单例确实是主要是减少对象在内存中的重复创建,避免创建过程中产生的内存、时间上的开销。
但是,单例我觉得更主要的还是因为应用场景的使用。毕竟,真正一个程序运行下来,就创建对象所耗费的时间,空间,在没有经过测试的情况下,是没发断定,他到底耗费了多少,以及这些耗费对我们的程序来说有什么影响。所以,这个地方,我觉得其实我们应该不用太过在意的。

我想说的在应用上的场景就是。比如,对于一次程序请求,这个请求声明周期中,会对某个对象的一些属性,要求不能重复出现。就是不能有多份的情况,那么单例的价值就出现了。每次,我们都是获取到的同一个对象,而不是每次都新出现的一个对象,导致对象属性由多个版本。

class User {
    protected $user_name;
    public function __construct()
    {
    }
}

比如这个类,我在新建了一个User 对象后,并给这个对象赋值了 user_name = 'Tomas'。后面我只想全局使用这同一个 User 对象。因为我需要的是他们的 user_name 属性,都是我开始赋值声明的那个值。
那么,如果我这里又能够 new User() ,就产生了一个新的 User 对象,那么对于新对象的 user_name 就不是我开始赋值的那个 Tomas 了,程序就会出错。单是一旦使用上了单例对象,那么不管怎么样,我全局都是获取的 user_name = 'Tomas' 这样一个 User 对象了。

class User {
    protected $user_name;
    public static $instance;
    
    private function __construct() {}  // 私有构造函数,避免多次创建对象,导致对象的不唯一
    private function clone() {}  // 避免克隆(保证单例对象的唯一性)

    public static function getInstance() { 
        if (null === self::$instance) {
            self::$instance = new self(); 
        }
        return self::$instance;
    }
}

但是可以保证每次请求都存在这个类的一个实例。

楼主说那用静态方法也是ok的。但是我想这样也抛弃了类的一些特有属性。比如构造函数,魔术方法等。而且我之前一段时间特别喜欢用静态写类。但是现在我还是喜欢用实例化类,因为抛弃了对象的一些特性。其实是得不偿失的。

还有一个原因是使用静态变量,在请求量大的时候,会容易遭成内存泄漏。所以,我建议还是使用单例比较好。尽量少使用静态方法。

我查过资料了,内存泄漏是错误的。特此说明。

含义:

作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是向单例类存储的实例返回一个引用

单例模式的三个要点:
  1. 需要保存类的唯一实例的静态成员变量

  2. 构造函数和克隆函数必须声明为私有的,防止外部程序 new 类从而失去单例的意义

  3. 必须提供一个访问这个实例的公共的静态方法(通常为 getInstance()),从而返回唯一实例的一个引用

private static $_instance;
private function __construct()
{
    echo "获得一个新对象";
}
private function __clone()
{
    // 覆盖clone()方法,禁止克隆
}
public static function getInstance()
{
    if (! (self::$_instance instanceof self)) {
        self::$_instance = new self();
    }
    return self::$_instance;
}
为什么要使用单例模式?

PHP 语言是一种解释型的脚本语言,这种运行机制使得每个 PHP 页面被解释执行后,所有的相关资源都会被回收。也就是说,PHP 在语言级别上没有办法让某个对象常驻内存,这和 JAVA 等编译型语言是不同的,比如在Java中单例会一直存在于整个应用程序的生命周期里,变量是跨页面级的,真正可以做到这个实例在应用程序生命周期中的唯一性。然而在PHP中,所有的变量无论是全局变量还是类的静态成员,都是页面级的,每次页面被执行时,都会重新建立新的对象,都会在页面执行完毕后被清空,这样似乎 PHP 单例模式就没有什么意义了,所以 PHP 单例模式我觉得只是针对单次页面级请求时出现多个应用场景并需要共享同一对象资源时是非常有意义的。

单例模式在PHP中的应用场合:

(1)应用程序与数据库交互

一个应用中会存在大量的数据库操作,比如过数据库句柄来连接数据库这一行为,使用单例模式可以避免大量的 new 操作,因为每一次 new 操作都会消耗内存资源和系统资源。

(2)控制配置信息

如果系统中需要有一个类来全局控制某些配置信息,那么使用单例模式可以很方便的实现。

假设有一个连接数据库的类,你和同伴共同编辑一个php文件,都要连接数据库,由于你不知道同伴有没有连接数据库,所有你连接了一遍数据库,同伴也不知道你有没有连接数据库,他也连接了一遍数据库,这是两个不同的连接。单例模式这时候就有用了。

推荐问题