Можно ли злоупотреблять поздней статической привязкой в PHP?

StackOverflow https://stackoverflow.com/questions/1816560

Вопрос

Начиная с версии 5.3, PHP поддерживает поздняя привязка для статических методов.Хотя это, несомненно, полезная функция, есть только несколько случаев, когда ее использование действительно необходимо (напримершаблон активной записи).

Рассмотрим эти примеры:

1.Конструкторы удобства (::create())

class SimpleObject
{
    public function __construct() { /* ... */ }

    public static function create()
    {
        return new static; // or: return new self;
    }
}

Если этот класс может быть расширен (однако он не расширяется ни одним классом в том же пакете), следует ли использовать позднюю статическую привязку просто для упрощения его расширения (без необходимости переписывать ::create() метод, и, что более важно, без необходимости помнить об этом)?

Примечание:эта идиома используется для обхода невозможности вызова методов для только что созданных объектов: new SimpleObject()->doStuff() недопустимо в PHP.


2.Константы класса

class TagMatcher
{
    const TAG_PATTERN = '/\<([a-z\-]+?)\>/i';

    private $subject;

    public function construct($subject) { $this->subject = $subject; }

    public function getAllTags()
    {
        $pattern = static::TAG_PATTERN;
        preg_match_all($pattern, $this->subject);
        return $pattern[1];
    }
}

Причина использования static:: в этом примере все аналогично предыдущему.Он используется только потому, что этот класс можно настроить так, чтобы он соответствовал тегам различной формы, просто расширив его и переопределив константу.


Итак, подводя итог, являются ли эти использования (и подобные им) поздней статической привязки излишеством?Есть ли какое-либо заметное снижение производительности?Кроме того, снижает ли частое использование поздней привязки общий прирост производительности, обеспечиваемый кэшами кода операции?

Это было полезно?

Решение

Итак, подводя итог, являются ли эти использования (и подобные им) поздней статической привязки излишеством?Есть ли какое-либо заметное снижение производительности?Кроме того, снижает ли частое использование поздней привязки общий прирост производительности, обеспечиваемый кэшами кода операции?

Введение поздней статической привязки исправляет недостаток в объектной модели PHP.Дело не в производительности, а в семантике.

Например, мне нравится использовать статические методы всякий раз, когда реализация метода не использует $this.Просто потому, что метод статичен, это не значит, что вы не хотите иногда его переопределять.До PHP 5.3 поведение заключалось в том, что при переопределении статического метода ошибка не отмечалась, но PHP просто продолжал бы и молча использовал родительскую версию.Например, приведенный ниже код выводит 'A' перед PHP 5.3.Это в высшей степени неожиданное поведение.

Поздняя статическая привязка исправляет это, и теперь тот же код выводит 'B'.

<?php
class A {
  public static function who() {
    echo __CLASS__;
  }
  public static function test() {
    static::who();
  }
}

class B extends A {
  public static function who() {
    echo __CLASS__;
  }
}

B::test();
?>

Другие советы

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

Редактировать чтобы ответить на вопрос Марко Демайо, как статический метод снижает тестируемость?

мне жаль, если для вас все это очевидно, статические члены (как данные, так и методы) являются полезны и не причиняют вреда при ответственном использовании, я намекал на их распространенное неправильное использование.

допустим, у вас есть веб-приложение, которое использует базу данных SQL.ваши бизнес-объекты могут извлекать данные с помощью статического интерфейса или с помощью полиморфизма.либо

class MyBusinessObject
extends...
{
  public function doThisOrThat(...)
  {
    $results = db::query('sql string...');
    ...
  }
}

или

class MyBusinessObject
extends...
{
  public function __construct(dbconn $db)
  {
    $this->db = $db;
  }
  private $db;
  public function doThisOrThat(...)
  {
    $results = $this->db->query('sql string...');
    ...
  }
}

последнее легче протестировать (как в:я хочу проверить, что строка sql, построенная из таких-то входных данных, является такой-то), потому что проще создать другую реализацию dbconn интерфейс, чем это является для изменения значения db::.зачем вам нужно то или другое?потому что вам не нужна реальная база данных для тестирования поведения при составлении sql, и на самом деле ее проще протестировать на без настоящая база данных.кроме того, проще отключить sql consumer, если ваши тесты касаются другого аспекта CUT (тестируемый код).

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

Где я нахожу необходимость использовать позднюю статическую привязку, так это разрешить издевательство над статическими методами для модульного тестирования с помощью PHPUnit.Проблема, с которой я сталкиваюсь, заключается в том, что мне не нравится строго изменять код, чтобы разрешить издевательство, но я могу с этим смириться.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top