用PHP扩展单例

Joh*_*ren 25 php inheritance singleton anti-patterns

我在一个Web应用程序框架中工作,其中一部分由许多服务组成,都是作为单例实现的.它们都扩展了一个Service类,其中实现了单例行为,看起来像这样:

class Service {
    protected static $instance;

    public function Service() {
        if (isset(self::$instance)) {
            throw new Exception('Please use Service::getInstance.');
        }
    }

    public static function &getInstance() {
        if (empty(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我有一个名为FileService的类实现如下:

class FileService extends Service {
    // Lots of neat stuff in here
}
Run Code Online (Sandbox Code Playgroud)

...调用FileService :: getInstance()不会像我想要的那样产生FileService实例,而是一个Service实例.我假设这里的问题是Service构造函数中使用的"self"关键字.

还有其他方法来实现我想要的东西吗?单例代码只有几行,但我仍然希望尽可能避免任何代码冗余.

Amy*_*y B 55

码:

abstract class Singleton
{
    protected function __construct()
    {
    }

    final public static function getInstance()
    {
        static $instances = array();

        $calledClass = get_called_class();

        if (!isset($instances[$calledClass]))
        {
            $instances[$calledClass] = new $calledClass();
        }

        return $instances[$calledClass];
    }

    final private function __clone()
    {
    }
}

class FileService extends Singleton
{
    // Lots of neat stuff in here
}

$fs = FileService::getInstance();
Run Code Online (Sandbox Code Playgroud)

如果你使用PHP <5.3,也添加它:

// get_called_class() is only in PHP >= 5.3.
if (!function_exists('get_called_class'))
{
    function get_called_class()
    {
        $bt = debug_backtrace();
        $l = 0;
        do
        {
            $l++;
            $lines = file($bt[$l]['file']);
            $callerLine = $lines[$bt[$l]['line']-1];
            preg_match('/([a-zA-Z0-9\_]+)::'.$bt[$l]['function'].'/', $callerLine, $matches);
        } while ($matches[1] === 'parent' && $matches[1]);

        return $matches[1];
    }
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*ren 8

如果我在5.3课程中得到更多关注,我会知道如何自己解决这个问题.使用PHP 5.3的新的后期静态绑定功能,我相信Coronatus的主张可以简化为:

class Singleton {
    protected static $instance;

    protected function __construct() { }

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

        return static::$instance;
    }

    final private function __clone() { }
}
Run Code Online (Sandbox Code Playgroud)

我试了一下,它就像一个魅力.不过,Pre 5.3仍然是一个完全不同的故事.

  • 对于所有子类,似乎只有一个字段`$ instance`,因此只返回首先调用`getInstance()`的类的单例. (5认同)