Когда вам нужно использовать позднюю статическую привязку? - PullRequest
9 голосов
/ 18 сентября 2008

После прочтения этого описания позднего статического связывания (LSB) я довольно ясно вижу, что происходит. Теперь, при каких обстоятельствах это может быть наиболее полезным или необходимым?

Ответы [ 6 ]

6 голосов
/ 18 сентября 2008

Мне нужен LSB для следующего сценария:

  • Представьте, что вы создаете "почтовый процессор", который загружает сообщение с почтового сервера, классифицирует его, анализирует, сохраняет и затем что-то делает, в зависимости от типа сообщения.
  • Иерархия классов: у вас есть базовый класс Message с дочерними элементами "BounceMessage" и "AcceptedMessage".
  • Каждый из типов сообщений имеет свой собственный способ сохранения себя на диске. Например, все сообщения типа BounceMessage пытаются сохранить себя как BounceMessage-id.xml. AcceptedMessage, с другой стороны, должен сохранять себя иначе - как AcceptedMessage-timestamp.xml. Здесь важно то, что логика определения шаблона имени файла различна для разных подклассов, но shared для всех элементов внутри подкласса. Вот почему имеет смысл использовать статический метод.
  • Базовый класс сообщений имеет абстрактный статический метод (да, абстрактный И статический) "save". BounceMessage реализует этот метод с помощью конкретного статического метода. Затем внутри класса, который фактически извлекает сообщение, вы можете вызвать ":: save ()"

Если вы хотите узнать больше о предмете:

5 голосов
/ 18 сентября 2008

Одной из основных потребностей, которые у меня есть для позднего статического связывания, является набор статических методов создания экземпляров.

Этот класс 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 уменьшает это дублирование и допускает более чистые и более простые реализации.

3 голосов
/ 18 сентября 2008

Это полезно, когда:

  1. У вас есть функциональность, которая варьируется в зависимости от иерархии классов,

  2. Функциональность имеет одинаковую сигнатуру в иерархии, и

  3. (крайне важно) У вас нет экземпляра для отключения функциональности.

Если бы только # 1 и # 2 были получены, вы бы использовали обычный метод экземпляра. Так что проблема Алекса (см. Его ответ на этот вопрос) не требует LSB.

Типичным случаем является создание объекта, когда подклассы создают себя разными способами, но с использованием одних и тех же параметров. Очевидно, у вас нет экземпляра для вызова, поэтому метод создания (также известный как фабричный метод) должен быть статическим. Тем не менее, вы хотите, чтобы его поведение варьировалось в зависимости от подкласса, поэтому обычный статический метод не подходит. См. Ответ Адама Франко для примера.

1 голос
/ 13 апреля 2009

Предположим, у вас есть классы, представляющие таблицы (экземпляры строк) в упрощенном объектно-реляционном преобразователе. У вас будет класс «Пользователь» и класс «Компания», экземпляры которых представляют строки соответствующих таблиц. Пользователь и Компания наследовали бы от некоторого базового абстрактного класса, скажем, «BaseObject», который будет иметь некоторые общие методы, такие как save (), delete (), validate () и т. Д.

Если вы хотите хранить данные о проверке и определении таблицы, лучшее место будет в статической переменной в каждом производном классе - поскольку проверка и определение таблицы одинаковы для каждого экземпляра пользователя.

Без LSB упомянутый метод validate () в BaseObject не будет иметь ссылки на статические переменные, определенные в User и Company, даже если вы вызываете его через экземпляр User. Он будет искать ту же статическую переменную в классе BaseObject и вызовет ошибку.

Это мой опыт работы с PHP 5.2.8 - LSB будет представлен в 5.3

1 голос
/ 18 сентября 2008

Если вам нужен доступ к перегруженному статическому свойству / методу в методе, который не был перегружен в подклассе - вам необходимо позднее статическое связывание. Быстрый пример: paste2.org

Классическим примером является класс ActiveRecord из Rails, если вы попытаетесь реализовать нечто подобное в PHP, которое будет выглядеть следующим образом: class User extends ActiveRecord, а затем попытаетесь вызвать User::find(1) метод, который вызывается, на самом деле ActiveRecord::find() потому что вы не перегружены find() в User - но без поздней статической привязки метод find() в ActiveRecord не может узнать, из какого класса он был вызван (self внутри него всегда будет указывать на ActiveRecord), и поэтому он не может получить ваш пользовательский объект для вас.

0 голосов
/ 21 мая 2009

У меня есть класс со статическим методом, который обрабатывает некоторое форматирование. У меня есть другой класс, который нуждается во всех функциональных возможностях исходного класса, за исключением того, как он обрабатывает форматирование.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...