Comments 61
Очень хорошая реализация, т.к. постоянное дублирование кода при наследовании, создании новых singleton'ов уже порядком надоело. Вместе с заплаткой для версий ниже 5.3.0 механизм получается универсальным.
-4
мне кажется вы спутали принципы наследования. Наследовать нужно только тогда когда ребенок является более специфической реализацией родителя. Например дверь — железная дверь. А у вас получается наследуем потому что все синглтоны, а что они реализуют вообще не важно.
+1
Согласен. Я сказал в постскриптуне, что наследование тут не самый удачный инструмент, но другого пути реализации в PHP я не вижу. У вас есть идеи?
0
я бы все таки использовал доступ к классам которые должны быть «синглтонами» через реестр. Zend_Registry как раз, например, для этого. Ибо в вашем случаем мне ничего не мешает сделать class MyClass extends Example и переопределить конструктор чтобы он мог создавать обьекты и тд и тп. Нет предела человеческой глупости :)
-2
Отвечу за автора =). Тут всё нормально: singleton — singleton для конфига.
-1
Лучше фабрику (абстрактную, если нужно).
+2
Если так надо, используйте IoC контейнеры, Registry и т.п.
Кроме того, если честно, не очень понятно в какой ситуации данное решение может пригодится. Для написания самих синглтонов делается один макрос в IDE…
Про использование OOP уже написали выше. Добавлю что private конструктор, который потом легко так переопределяется в классах-потомках, сильно удивляет. Точнее, путает.
Да, и автоподстановка в IDE работать не будет в вашем случае. Ибо у метода getInstance() в документации не указать возвращаемый тип.
ЗЫ: Ваши строчки про аннотации из какого языка взяты? Java? В этом случае эти строчки вызывают крайне много вопросов.
Кроме того, если честно, не очень понятно в какой ситуации данное решение может пригодится. Для написания самих синглтонов делается один макрос в IDE…
Про использование OOP уже написали выше. Добавлю что private конструктор, который потом легко так переопределяется в классах-потомках, сильно удивляет. Точнее, путает.
Да, и автоподстановка в IDE работать не будет в вашем случае. Ибо у метода getInstance() в документации не указать возвращаемый тип.
ЗЫ: Ваши строчки про аннотации из какого языка взяты? Java? В этом случае эти строчки вызывают крайне много вопросов.
+6
сейчас на меня набросятся люди с топорами, НО:
class A
{
static $data;
static Bla()
{
echo self::$data;
}
static Init($str)
{
static $inited = false;
if(!$inited)
self::$data = $str;
}
}
A::Init('test');
в принципе такой код полностью симулирует синглтон, при этом его всё ещё можно наследовать и конструировать, тоесть разницы никакой, ну разве что
$a = new A;
$a->method();
или
A::method();
а собсна что вам нравится решайте сами
class A
{
static $data;
static Bla()
{
echo self::$data;
}
static Init($str)
{
static $inited = false;
if(!$inited)
self::$data = $str;
}
}
A::Init('test');
в принципе такой код полностью симулирует синглтон, при этом его всё ещё можно наследовать и конструировать, тоесть разницы никакой, ну разве что
$a = new A;
$a->method();
или
A::method();
а собсна что вам нравится решайте сами
0
ИМХО, синглтоны не стоят того, чтобы из-за них так мучиться.
Ибо, как всем известно, в php5 нет пронстранств имен и синглтоны ни чем не лучше использования глобальных переменных. Введете 2 синглтона с одинаковыми именами и придется делать рефакторинг всего проекта (((
Так что смысл синглтонами делать только классы шаблона Register, а в них уже хранить ссылки на остальные синглтоны.
Подробнее в книге www.books.ru/shop/books/693675
Ибо, как всем известно, в php5 нет пронстранств имен и синглтоны ни чем не лучше использования глобальных переменных. Введете 2 синглтона с одинаковыми именами и придется делать рефакторинг всего проекта (((
Так что смысл синглтонами делать только классы шаблона Register, а в них уже хранить ссылки на остальные синглтоны.
Подробнее в книге www.books.ru/shop/books/693675
0
чтобы Singelton ваш был единственным используйте IoC(DI)
0
Буду очень, очень бладгодарен за пример инверсии контроля приминительно к данному случаю на PHP.
0
Очень хорошо всё описано в документации компонента Dependency Injection. Очень рекомендую.
+1
Если бы речь шла о Java + Spring, то проблема, на сколько мне известно, действительно решалась бы объявлением следующего baen'а:
<bean id="example" class="package.ExampleImpl" singleton="true">
…
</bean>
Но в данном случае речь о не о Java.
<bean id="example" class="package.ExampleImpl" singleton="true">
…
</bean>
Но в данном случае речь о не о Java.
0
Вместо is_a() лучше использовать instanceof, ЕМНИП :)
0
Не стоит делать конструктор приватным, т.к. его нельзя будет переопределить в дочерних классах. Исправьте на протектед.
0
Когда количество синглтонов в проекте расте пропорционально сложности и размеру, стоит пересмотреть подход к архитектуре, т.к. подобный способ ломает модульность кода и сильно мешает юнит тестированию.
По-хорошему, класс должен сам знать все свои депенденси, так что особой нужды в жутких количествах синглтонов нет.
По-хорошему, класс должен сам знать все свои депенденси, так что особой нужды в жутких количествах синглтонов нет.
0
ну кстати ни разу не правы
модульность кода может достигаться за счёт использования указателей на объект
а вот класс не всегда знает свои зависимости, допустим если один и тот же класс работает с разными базами данных
тогда только 2 решения — или прокси на нужную базу или указатель на синглет работы с БД
модульность кода может достигаться за счёт использования указателей на объект
а вот класс не всегда знает свои зависимости, допустим если один и тот же класс работает с разными базами данных
тогда только 2 решения — или прокси на нужную базу или указатель на синглет работы с БД
0
>> модульность кода может достигаться за счёт использования указателей на объект
не понял мысль
>> а вот класс не всегда знает свои зависимости, допустим если один и тот же класс работает с разными базами данных
>> тогда только 2 решения — или прокси на нужную базу или указатель на синглет работы с БД
решение в духе ООП для такой ситуации — это интерфейс
синглтон для этого не нужен. Интерфейсов в пхп для БД много — PEAR::DB, adodb…
не понял мысль
>> а вот класс не всегда знает свои зависимости, допустим если один и тот же класс работает с разными базами данных
>> тогда только 2 решения — или прокси на нужную базу или указатель на синглет работы с БД
решение в духе ООП для такой ситуации — это интерфейс
синглтон для этого не нужен. Интерфейсов в пхп для БД много — PEAR::DB, adodb…
0
В PHP 5.3.0 для позднего статического связывания появился референс static:: который резолвится именно так, как надо.
php.net/manual/en/language.oop5.late-static-bindings.php
php.net/manual/en/language.oop5.late-static-bindings.php
+1
Да, но для получения имени вызываемого класса использовать его не получится.
-1
Для создания синглтона это и не требуется
+1
Уверены? Можно пример?
-1
class Sin
{
public $a = 1;
static private $_instance;
static function getInstance()
{
if (! self::$_instance ) {
self::$_instance = new static; // тут только начиная с php 5.3.*
}
return self::$_instance;
}
}
class B extends Sin
{
public $a = 2;
}
$s = B::getInstance();
var_dump($s);
{
public $a = 1;
static private $_instance;
static function getInstance()
{
if (! self::$_instance ) {
self::$_instance = new static; // тут только начиная с php 5.3.*
}
return self::$_instance;
}
}
class B extends Sin
{
public $a = 2;
}
$s = B::getInstance();
var_dump($s);
+2
Опередили :)
0
А почему вы пишете:
а не
Или
if (! self::$_instance ) {
self::$_instance = new static; // тут только начиная с php 5.3.*
а не
if (! static::$_instance ) {
static::$_instance = new static();
?Или
static::
работает только для методов, но не для полей? А скобочки после new static
не нужны?0
Оба способа монописуальны, так как при создании класса с помощью конструкции new в случае отсутствия параметров скобки можно опускать:
ini_set('display_errors', 1);
error_reporting(E_ALL | E_STRICT);
class Test {
function __construct() {
echo 'Test Constructor', "\n";
}
}
$oTest1 = new Test(); // Печатает 'Test Constructor'
$oTest2 = new Test; // Печатает 'Test Constructor'
ini_set('display_errors', 1);
error_reporting(E_ALL | E_STRICT);
class Test {
function __construct() {
echo 'Test Constructor', "\n";
}
}
$oTest1 = new Test(); // Печатает 'Test Constructor'
$oTest2 = new Test; // Печатает 'Test Constructor'
0
Потому что $_instance приватное свойство класса Sin, и не доступно для потомков. Вообще можно объявить $_instance как protected, тогда можно будет использовать static::$_instance. Я просто хотел чтобы было как у автора (private свойство), он вроде тоже об этом упоминает.
> А скобочки после new static не нужны?
Как вам больше нравиться =) Классы можно создавать и так и так. Т.е:
class B {}
$a = new B;
тоже вполне допустимо.
> Или static:: работает только для методов, но не для полей?
Нет, работает и так и так, как я уже писал здесь self только из-за того что поле private.
> А скобочки после new static не нужны?
Как вам больше нравиться =) Классы можно создавать и так и так. Т.е:
class B {}
$a = new B;
тоже вполне допустимо.
> Или static:: работает только для методов, но не для полей?
Нет, работает и так и так, как я уже писал здесь self только из-за того что поле private.
0
Да, не заметил приватности инстанции.
А в случае
Хотя все эти вопросы чисто теоретические — мне вряд ли светит переход на php6 :)
А в случае
self::$_instance
не перепишется приватное поле родительского класса?Хотя все эти вопросы чисто теоретические — мне вряд ли светит переход на php6 :)
0
> Хотя все эти вопросы чисто теоретические — мне вряд ли светит переход на php6 :)
Ну в общем то php6 тут и не нужен, хватит php 5.3.
> А в случае self::$_instance не перепишется приватное поле родительского класса?
Гм, я не уверен, что понял, что именно вы спрашиваете. Если объявить в классе B static private $_instance, то нет, ничего не перепишется. Обращаясь к B self::$_instance и к Sin self::$_instance вы получите. Т.е когда модификатор свойства private потомок не может напрямую получить доступ к нему.
Ну в общем то php6 тут и не нужен, хватит php 5.3.
> А в случае self::$_instance не перепишется приватное поле родительского класса?
Гм, я не уверен, что понял, что именно вы спрашиваете. Если объявить в классе B static private $_instance, то нет, ничего не перепишется. Обращаясь к B self::$_instance и к Sin self::$_instance вы получите. Т.е когда модификатор свойства private потомок не может напрямую получить доступ к нему.
class Sin
{
static private $_instance = 'Sin $_instance';
public function test()
{
return self::$_instance;
}
}
class B extends Sin
{
static protected $_instance = 'B $_instance';
public function test2()
{
return self::$_instance;
}
}
$s = new B;
var_dump($s->test()); // Sin $_instance
echo '<Br>';
var_dump($s->test2()); // B $_instance
0
В промежуточном переходе на php5.3 смысла я не вижу, мне интересней нативная поддержка юникода в php6 — часто сталкиваюсь с проблемами с восточноевропейскими кодировками.
Вопрос был в другом:
Мне кажется, что переменные $b и $sin будут имет одно и то же значение — инстанцию класса B, так как он создастся раньше, но сохранится в общей для них поле self::$_instance в классе Sin.
Вопрос был в другом:
class Sin
{
public $a = 1;
static private $_instance;
static function getInstance()
{
if (! self::$_instance ) {
self::$_instance = new static; // тут только начиная с php 5.3.*
}
return self::$_instance;
}
}
class B extends Sin
{
public $a = 2;
}
$b = B::getInstance();
$sin = Sin::getInstance();
Мне кажется, что переменные $b и $sin будут имет одно и то же значение — инстанцию класса B, так как он создастся раньше, но сохранится в общей для них поле self::$_instance в классе Sin.
0
Вот, теперь все ясно. Отвечаю (раз уж начал, то до конца) =) Да вы правы, и действительно свойство $_instance будет одно на всех. Для того чтобы это избежать, нужно делать что-то вроде, того что привел автор. Ну или объявлять static protected $_instance в потомках (и в родительском классе), и так же использовать везде static:: вместо self::. Я думаю можно еще найти какие-то способы, но все они мне почему-то не очень нравятся, ибо помахивают каким-то не здравым шаманством.
0
Еще один Singleton. Крутой пример, он несколько по другому подходит к проблеме. Используется static «внутри» функции.
0
На сколько мне известно ввиду того, что некоторые нововведения, которые планировались в 6-ой версии, были бэкпортированы в 5-ую, сколь-либо скорого появления 6-ой версии ихо ожидать не стоит.
0
а мне нравится такой вариант:
$example_obj= $core->new_example;
где ядро самостоятельно находит файл 'inc/example.php', исполняет его получая имя класса, инстанцирует и кэширует результат.
$example_obj= $core->new_example;
где ядро самостоятельно находит файл 'inc/example.php', исполняет его получая имя класса, инстанцирует и кэширует результат.
0
Ох, уж эти префиксы в названиях переменных.
0
Чем дальше, тем все больше убеждаюсь, что singleton не для web. Он больше мешает, чем приносит пользы.
-1
Sign up to leave a comment.
Singleton и Late static binding