tl;dr Использовать ли статические методы? Да, когда они не зависят от внутреннего состояния объекта.

В обсуждениях к посту (перевод) о именованных конструкторах прозвучало мнение, что статические методы плохи и их вообще не стоит использовать. На мой взгляд, это слишком большое обобщение.

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

Основная проблема здесь — отсутствие совместно используемого глобального состояния. Вот пример из прошлого поста:

<?php
$time = Time::from("11:45");

В данном примере возвращаемый результат свободен от побочных эффектов и вполне предсказуем, т.к. зависит только от аргументов, подаваемых на вход. Каждый раз при вызове метода вам будет возвращен идентичный результат (объект Time со значением 11:45), вне зависимости от состояния системы, контекста или чего-либо еще.

Другой пример:

<?php
$sum = Calculator::sum(1, 2); 

И снова — результат предсказуем, Calculator::sum(1, 2); предоставляет нам сервис, не имеющий состояния, и не зависящий ни от чего, кроме аргументов. Более того, эта реализация не может быть полиморфной или иметь различные имплементации, т.к. любой результат кроме 3 будет ошибкой. Да, вы можете изменить внутреннюю реализацию метода, улучшив алгоритм сложения чисел, но это не должно никак отражаться на результате его использования.

Возьмем обратный пример, на этот раз с состоянием:

<?php
Counter::increment(1);
$count = Counter::getCount();

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

Абстракция


Возможно, вы все еще чувствуете неприятие против кода, вроде Calculator::sum($x, $y), т.к. мы не можем сымитировать или расширить его. Но не стоит забывать, что это довольно низкий уровень абстракции. Вы также не сможете сымитировать и расширить оператор + в PHP, но я не думаю, что вы когда-либо чувствовали потребность в этом. Если вам нужен более высокий уровень абстракции, то композиция — ваш верный спутник. Но хочу заметить, между Calculator::sum($x, $y) и + есть довольно интересное различие, первый может вот так, а второй нет:

<?php
$result = array_reduce([1,2,3], 'Calculator::sum', 0);
// $result = 6

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


Часть 1: Как использовать именованные конструкторы в PHP

Комментарии (44)