如何使用PHP5类创建单例类?


当前回答

我同意第一个答案,但我也会将类声明为final,这样它就不能被扩展,因为扩展单例违背了单例模式。此外,实例变量应该是私有的,这样就不能直接访问它。还要将__clone方法设为私有,这样就不能克隆单例对象。

下面是一些示例代码。

/**
 * Singleton class
 *
 */
final class UserFactory
{
    private static $_instance = null;

    /**
     * Private constructor
     *
     */
    private function __construct() {}

    /**
     * Private clone method
     *
     */
     private function __clone() {}

    /**
     * Call this method to get singleton
     *
     * @return UserFactory
     */
    public static function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new UserFactory();
        }
        return self::$_instance;
    }
}

示例使用

$user_factory = UserFactory::getInstance();

这阻止你做什么(这将违反单例模式..

你不能这么做!

$user_factory = UserFactory::$_instance;

class SecondUserFactory extends UserFactory { }

其他回答

我同意第一个答案,但我也会将类声明为final,这样它就不能被扩展,因为扩展单例违背了单例模式。此外,实例变量应该是私有的,这样就不能直接访问它。还要将__clone方法设为私有,这样就不能克隆单例对象。

下面是一些示例代码。

/**
 * Singleton class
 *
 */
final class UserFactory
{
    private static $_instance = null;

    /**
     * Private constructor
     *
     */
    private function __construct() {}

    /**
     * Private clone method
     *
     */
     private function __clone() {}

    /**
     * Call this method to get singleton
     *
     * @return UserFactory
     */
    public static function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new UserFactory();
        }
        return self::$_instance;
    }
}

示例使用

$user_factory = UserFactory::getInstance();

这阻止你做什么(这将违反单例模式..

你不能这么做!

$user_factory = UserFactory::$_instance;

class SecondUserFactory extends UserFactory { }

这篇文章涵盖了相当广泛的主题: http://www.phptherightway.com/pages/Design-Patterns.html#singleton

Note the following: The constructor __construct() is declared as protected to prevent creating a new instance outside of the class via the new operator. The magic method __clone() is declared as private to prevent cloning of an instance of the class via the clone operator. The magic method __wakeup() is declared as private to prevent unserializing of an instance of the class via the global function unserialize(). A new instance is created via late static binding in the static creation method getInstance() with the keyword static. This allows the subclassing of the class Singleton in the example.

以上答案都是可以的,但我还会再补充一些。

无论谁在2021年来到这里,我都将展示另一个使用单例模式类作为trait的例子,并在任何类中重用它。

<?php

namespace Akash;

trait Singleton
{
    /**
     * Singleton Instance
     *
     * @var Singleton
     */
    private static $instance;

    /**
     * Private Constructor
     *
     * We can't use the constructor to create an instance of the class
     *
     * @return void
     */
    private function __construct()
    {
        // Don't do anything, we don't want to be initialized
    }

    /**
     * Get the singleton instance
     *
     * @return Singleton
     */
    public static function getInstance()
    {
        if (!isset(self::$instance)) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    /**
     * Private clone method to prevent cloning of the instance of the
     * Singleton instance.
     *
     * @return void
     */
    private function __clone()
    {
        // Don't do anything, we don't want to be cloned
    }

    /**
     * Private unserialize method to prevent unserializing of the Singleton
     * instance.
     *
     * @return void
     */
    private function __wakeup()
    {
        // Don't do anything, we don't want to be unserialized
    }
}

所以,像在任何课堂上一样轻松地使用它。假设,我们想在UserSeeder类中实现单例模式。

<?php

class UserSeeder
{
    use Singleton;

    /**
     * Seed Users
     *
     * @return void
     */
    public function seed()
    {
        echo 'Seeding...';
    }
}

PHP 5.3允许通过后期静态绑定创建可继承的单例类:

class Singleton
{
    protected static $instance = null;

    protected function __construct()
    {
        //Thou shalt not construct that which is unconstructable!
    }

    protected function __clone()
    {
        //Me not like clones! Me smash clones!
    }

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

这解决了一个问题,在PHP 5.3之前,任何扩展了Singleton的类都会生成父类的实例,而不是它自己的实例。

现在你可以做:

class Foobar extends Singleton {};
$foo = Foobar::getInstance();

$foo将是Foobar的一个实例而不是Singleton的一个实例。

下面是我的例子,它提供了调用as $var = new Singleton()的能力,并创建了3个变量来测试它是否创建了新对象:

class Singleton{

    private static $data;

    function __construct(){
        if ($this::$data == null){
            $this->makeSingleton();
        }
        echo "<br/>".$this::$data;
    }

    private function makeSingleton(){
        $this::$data = rand(0, 100);
    }

    public function change($new_val){
        $this::$data = $new_val;
    }

    public function printme(){
        echo "<br/>".$this::$data;
    }

}


$a = new Singleton();
$b = new Singleton();
$c = new Singleton();

$a->change(-2);
$a->printme();
$b->printme();

$d = new Singleton();
$d->printme();