Rozszerzanie singletonów w PHP
Pracuję w Web app framework, a część z nich składa się z szeregu usług, wszystkie zaimplementowane jako singletony. Wszystkie one rozszerzają klasę usług, w której zaimplementowane jest zachowanie Singletona, wyglądając mniej więcej tak:
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;
}
}
Teraz, jeśli mam klasę o nazwie FileService zaimplementowaną TAK:
class FileService extends Service {
// Lots of neat stuff in here
}
... wywołanie metody FileService:: getInstance() nie wyda instancji FileService, tak jak tego chcę, ale instancji Service. Zakładam, że problemem jest tutaj "ja"" słowo kluczowe użyte w konstruktorze usługi.
Czy jest jakiś inny sposób, aby osiągnąć to, czego chcę? Kod Singletona to tylko kilka linijek, ale nadal chciałbym uniknąć redundancji kodu, kiedy tylko mogę.4 answers
Kod:
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();
Jeśli używasz PHP
// 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];
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-24 02:50:39
Gdybym poświęciła więcej uwagi w klasie 5.3, wiedziałabym, jak to rozwiązać. Korzystając z nowej funkcji późnego wiązania statycznego w PHP 5.3, wierzę, że propozycję Coronatusa można uprościć do tego:
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() { }
}
Wypróbowałem go i działa jak czar. Pre 5.3 to jednak zupełnie inna historia.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-09 21:33:47
To stała odpowiedź Johana. PHP 5.3 +
abstract class Singleton
{
protected function __construct() {}
final protected function __clone() {}
final public static function getInstance()
{
static $instance = null;
if (null === $instance)
{
$instance = new static();
}
return $instance;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-21 23:58:56
Znalazłem dobre rozwiązanie.
Oto Mój kod
abstract class Singleton
{
protected static $instance; // must be protected static property ,since we must use static::$instance, private property will be error
private function __construct(){} //must be private !!! [very important],otherwise we can create new father instance in it's Child class
final protected function __clone(){} #restrict clone
public static function getInstance()
{
#must use static::$instance ,can not use self::$instance,self::$instance will always be Father's static property
if (! static::$instance instanceof static) {
static::$instance = new static();
}
return static::$instance;
}
}
class A extends Singleton
{
protected static $instance; #must redefined property
}
class B extends A
{
protected static $instance;
}
$a = A::getInstance();
$b = B::getInstance();
$c = B::getInstance();
$d = A::getInstance();
$e = A::getInstance();
echo "-------";
var_dump($a,$b,$c,$d,$e);
#object(A)#1 (0) { }
#object(B)#2 (0) { }
#object(B)#2 (0) { }
#object(A)#1 (0) { }
#object(A)#1 (0) { }
Możesz polecić http://php.net/manual/en/language.oop5.late-static-bindings.php więcej informacji
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-19 06:52:21