Позднее статическое связывание PHP в синглтоне

У меня есть этот код из какой-то статьи на habrahabr.ru:

abstract class Singleton {

    protected static $_instances = array();

    protected function __construct() {
    }

    public static function getInstance() {

            $class = \get_called_class();
            if ( !isset( static::$_instances[$class] ) )
                    static::$_instances[$class] = new static;

            return static::$_instances[$class];

    }

}

Автор использует его как, например,

class B extends Singleton {

    private $_a = 10;

}

Но я не могу понять основную разницу между "static" и "self" в этом случае: например, если мы определим $_instances как общедоступный и попытаемся создать какой-то другой класс, например

class C extends Singleton {

    private $_z =  55;

}

и определяем Singleton как не абстрактный класс, после каждого вызова getInstance мы имеем один и тот же массив экземпляров в обоих случаях: со static::$_instances и self::$_instances:

$s = Singleton::getInstance();

print_r(Singleton::$_instances);
print_r(B::$_instances);
print_r(C::$_instances);

$b_instance = B::getInstance();

print_r(Singleton::$_instances);
print_r(B::$_instances);
print_r(C::$_instances);

$c_instance = C::getInstance();

print_r(Singleton::$_instances);
print_r(B::$_instances);
print_r(C::$_instances);

Может ли кто-нибудь помочь мне и сказать мне, почему массивы $_instances одинаковы, и почему автор использует статические, а не собственные? Большое спасибо, извините за мой английский.


person Guy Fawkes    schedule 01.03.2011    source источник
comment
возможный дубликат Что такое поздняя статическая привязка в PHP?   -  person Gordon    schedule 01.03.2011
comment
Нет, это не дубликат. Я знаю, что такое LSB. Я задал другой вопрос.   -  person Guy Fawkes    schedule 02.03.2011
comment
Если вы считаете, что это не дубликат, уточните вопрос, а не просто говорите «Нет, это не так». Вы не получили никаких других ответов, кроме того, который я только что удалил, так что либо мы все тупые, либо ваш вопрос не ясен. Ваш выбор.   -  person Gordon    schedule 02.03.2011
comment
Я не знаю, как описать вопрос другими словами, если вопрос строгий, а не о ПОМОГИТЕ МНЕ Я НЕ ХОЧУ ЧИТАТЬ ДОКУМЕНТЫ, ЧТО ТАКОЕ LSB???77   -  person Guy Fawkes    schedule 03.03.2011


Ответы (1)


Все классы совместно используют один и тот же статический массив $_instances, содержащийся в классе Singleton. Причина, по которой автор использовал «новую статику»; должен был хранить объект вызываемого класса в этом массиве. Поскольку существует только один массив, вызовы self:: и static:: для этого массива из класса Singleton вернут одни и те же данные.

Итак, чтобы уточнить, когда вы звоните:

$b_instance = B::getInstance();

экземпляр B добавляется в массив $_instances, хранящийся в Singleton. Если вы добавите статическое свойство $_instances в класс B или C, поведение будет другим, поскольку вновь созданный экземпляр будет храниться внутри статического свойства $_instances своего собственного класса.

person Jeff Parker    schedule 02.03.2011
comment
Большое Вам спасибо. Но, как последний вопрос: если я пишу static::$_instances, PHP интерпретирует это как массив экземпляров B, когда вызывается B::getInstance(), или массив экземпляров Singleton? Я думаю, массив в B, не так ли? - person Guy Fawkes; 03.03.2011
comment
Нет, массив в Singleton, поскольку B не имеет своих собственных $_instances... когда вы вызываете B::$_instances или static::$_instances из B, он будет ссылаться на тот, что находится в Singleton. Это было бы иначе, только если бы вы явно определили $_instances в B. - person Jeff Parker; 03.03.2011
comment
Не могу понять идеологию: статика написана в методе синглтона, поэтому когда этот метод вызывается из Б, почему статика не ссылается на Б? - person Guy Fawkes; 03.03.2011
comment
Он ссылается на B, но поскольку B не включает определение $_instances, он передается родительскому классу Singleton. Если вы добавите $_instances в B, тогда все будет по-другому, но в действительности B имеет доступ только к $_instances, потому что в Singleton есть экземпляр. Один экземпляр $_instances, общий для всех подклассов, у которых нет собственного экземпляра. - person Jeff Parker; 03.03.2011
comment
добавить защищенный статический $_instances = array(); на B и/или C и повторно запустите свой пример. Вы должны видеть, что я имею в виду. - person Jeff Parker; 03.03.2011
comment
О, я вижу. Но что мне делать, если я хочу работать из метода Singleton с массивом в B? - person Guy Fawkes; 03.03.2011
comment
Просто добавьте защищенный статический $_instances = array(); на Б, если это так. Любые вызовы static::$_instances, проходящие через B, будут сохранены в B. - person Jeff Parker; 03.03.2011
comment
Мне жаль! :) Я использовал self, не static. Теперь я все понимаю. Спасибо. - person Guy Fawkes; 03.03.2011