Возможно ли использовать чрезмерное статическое связывание в PHP?

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

Рассмотрим следующие примеры:

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

 class SimpleObject { public function __construct() { /* ... */ } public static function create() { return new static; // or: return new self; } } 

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

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


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

 class TagMatcher { const TAG_PATTERN = '/\<([az\-]+?)\>/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, если ваши тесты касаются другого аспекта CUT (Code In Test).

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

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

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