Прочитав это описание позднего статического привязки (LSB), я довольно четко вижу, что происходит. Теперь, при каких обстоятельствах это может быть самым полезным или необходимым?
Мне нужен LSB для следующего сценария:
Если вы хотите узнать больше о предмете:
Одна из основных проблем, которые я испытываю для поздней статической привязки, – это набор статических методов создания экземпляров.
Этот класс DateAndTime является частью библиотеки хронологии, которую я портировал на PHP из Smalltalk / Squeak. Использование статических методов создания экземпляров позволяет создавать экземпляры с различными типами аргументов, сохраняя при этом проверку параметров в статическом методе, чтобы потребитель библиотеки не смог получить экземпляр, который не является полностью действительным.
Позднее статическое связывание полезно в этом случае, так что реализации этих статических методов создания экземпляров могут определять, из какого класса изначально был направлен вызов. Вот пример использования:
С LSB:
class DateAndTime { public static function now() { $class = static::myClass(); $obj = new $class; $obj->setSeconds(time()); return $obj; } public static function yesterday() { $class = static::myClass(); $obj = new $class; $obj->setSeconds(time() - 86400); return $obj; } protected static function myClass () { return 'DateAndTime'; } } class Timestamp extends DateAndTime { protected static function myClass () { return 'Timestamp'; } } // Usage: $date = DateAndTime::now(); $timestamp = Timestamp::now(); $date2 = DateAndTime::yesterday(); $timestamp2 = Timestamp::yesterday();
Без поздней статической привязки [как и в моей текущей реализации] каждый класс должен реализовать каждый способ создания экземпляра, как в этом примере:
Без LSB:
class DateAndTime { public static function now($class = 'DateAndTime') { $obj = new $class; $obj->setSeconds(time()); return $obj; } public static function yesterday($class = 'DateAndTime') { $obj = new $class; $obj->setSeconds(time() - 86400); return $obj; } } class Timestamp extends DateAndTime { public static function now($class = 'Timestamp') { return self::now($class); } public static function yesterday($class = 'Timestamp') { return self::yesterday($class); } }
По мере увеличения количества методов создания экземпляров и иерархии классов дублирование методов становится настоящей болью в прикладе. LSB уменьшает это дублирование и обеспечивает гораздо более чистые и более прямые реализации.
Это полезно, когда:
У вас есть функциональность, которая зависит от иерархии классов,
Функциональность имеет одну и ту же подпись по иерархии и
(критически) У вас нет экземпляра, чтобы отключить функциональность.
Если получены только # 1 и # 2, вы должны использовать обычный метод экземпляра. Поэтому проблема Алекса (см. Его ответ на этот вопрос) не требует LSB.
Типичным случаем является создание объекта, где подклассы создают себя по-разному, но используют одни и те же параметры. Очевидно, что у вас нет экземпляра для вызова, поэтому метод создания (также известный как заводский метод) должен быть статическим. Тем не менее вы хотите, чтобы его поведение менялось в зависимости от подкласса, поэтому обычный статический метод неверен. См. Ответ Адама Франко для примера.
Если вам нужно получить доступ к перегруженному статическому свойству / методу в методе, который не был перегружен в подклассе, вам потребуется поздняя статическая привязка. Быстрый пример: paste2.org
Классическим примером является класс ActiveRecord из Rails, если вы попытаетесь реализовать что-то подобное в PHP, которое будет выглядеть так: class User extends ActiveRecord
а затем пытается вызвать User::find(1)
метод, который вызывается, фактически является ActiveRecord::find()
потому что вы не перегрузили find()
в User
но без поздней статической привязки метод find()
в ActiveRecord
не имеет способа узнать, из какого класса он вызван (изнутри внутри всегда будет указываться ActiveRecord
) , и, следовательно, он не может получить ваш Пользовательский объект для вас.
Предположим, что у вас есть классы, представляющие таблицы (экземпляры строк) в упрощенном объектно-реляционном сопоставлении. У вас будет класс «Пользователь» и класс «Компания», экземпляры которого представляют строки соответствующих таблиц. Пользователь и компания наследуют от базового абстрактного класса, скажем, «BaseObject», который будет иметь некоторые общие методы, такие как save (), delete (), validate () и т. Д. …
Если вы хотите хранить данные о проверке и определении таблицы, лучшим местом будет статическая переменная в каждом производном классе, поскольку определение валидации и таблицы одинаково для каждого экземпляра пользователя.
Без LSB упомянутый метод validate () в BaseObject не будет ссылаться на статические переменные, определенные в User and Company, даже если вы вызываете его через экземпляр User. Он будет искать одну и ту же статическую переменную в классе BaseObject, и это вызовет ошибку.
Это мой опыт работы с PHP 5.2.8 – LSB будет представлен в 5.3
У меня есть класс со статическим методом, который обрабатывает некоторое форматирование. У меня есть другой класс, который требует всех функциональных возможностей оригинала, за исключением того, как он обрабатывает форматирование.