В мире существуют две разновидности PHP-разработчиков. Одни предпочитают статические методы, потому что с ними легко работать, другие же, напротив, считают статические методы — зло и не используют их в своей практике.
В этой статье попробую, используя опыт работы с несколькими фреймворками, объяснить, почему некоторые разработчики игнорируют лучшие практики и используют целую кучу статических методов.
Кто любит статические методы?
Особенно часто их применяют разработчики, которые когда-либо использовали в своей работе фреймворк CodeIgniter.
Также, в число последователей статистических методов входят большинство Kohana- и Laravel-разработчиков.
Тут нельзя не упомянуть тот факт, что программисты, которые решают начать писать собственные вещи, обычно отказываются от использования CodeIgniter.
Почему, спросите вы?
CodeIgniter поддерживал PHP 4 до того, как статические методы были добавлены в PHP 5. Кроме того, CodeIgniter использует «супер-объект», который предоставляет равный доступ всем классам, назначенным контроллеру. Таким образом они становится доступными к использованию в рамках всей системы.
Это означает, что классы могут быть доступны из любой модели с помощью метода __get(), который будет искать запрашиваемое свойство с помощью get_instance()->{$var}. Ранее, когда поддержки функции __get() не было в PHP 4, для этого использовалась конструкция foreach через параметры CI_Controller, а затем они назначались переменной $this в модели.
В библиотеке вы должны вызвать get_instance. Библиотека не наследует класс в принудительном порядке, поэтому нет никакого способа обойти функцию __get().
Объем…
Получается довольно громоздкая конструкция для доступа к коду. Точно такой же функциональности без дополнительных усилий можно достичь с помощью статического метода.
Да и нет особого смысла рассуждать о такой конструкции. Хорошо, вы можете получить доступ к данным сессии в своей модели. Но зачем вам это делать?
«Решение»
Kohana-разработчики были первыми, кто серьезно поработал над статическими методами. Они внесли следующие изменения:
//было
$this->input->get('foo');
// стало
Input::get('foo');
Для многих CodeIgniter-разработчиков с их устаревшим PHP 4, которые переехали на фреймфорк Kohana, чтобы пользоваться всеми прелестями PHP 5, в этом ничего необычного нет. Но ведь, чем меньше символов, тем лучше, так?
И в чем же проблема?
Многие PHP-разработчики (особенно те, кто хорошо разбирается в Symfony и Zend) скажут: « Это же очевидно — используй Внедрение зависимостей!» Но не многие разработчики в сообществе CodeIgniter имеют реальный опыт работы с этим процессом, так как он довольно сложен.
Еще один факт о фреймворке Fuel PHP — пока в основном статические методы выступают в качестве интерфейса. Например, логика все еще имеет проблемы со статикой, особенно когда задействуется концепция HMVC.
Это псевдокод, который я не использовал в FuelPHP, начиная с версии 1.1:
class ControllerA extends Controller
{
public function action_foo()
{
echo Input::get('param');
}
}
Довольно стандартный код. Этот метод будет выводить значение ?bar= в методе.
Что происходит, когда мы делаем HMVC-запрос к данному методу?
class ControllerB extends Controller
{
public function action_baz()
{
echo Input::get('param');
echo " & ";
echo Request::forge('controllera/foo?param=val1')->execute();
}
}
Вызвав в браузере controllerb/baz, вы увидите вывод «val1», но если вы наберете controllerb/baz?param=override, то получите оба вызова для получения метода, возвращающего то же самое значение.
Актуальность
Глобальный код не даст вам какого-либо отношения. Пример лучше любых слов:
$this->request->input->get('param');
Запрошенный объект будет содержать совершенно новый экземпляр для каждого запроса, тогда ввод объекта будет создаваться для каждого запроса, который содержит только входные данные для конкретного запроса. Это справедливо для FuelPHP 2.0 plans to work и решает проблему Внедрения зависимостей, а также проблемы с HMVC.
Как быть с грубым синтаксисом?
Symfony- или Zend- разработчики таким не страдают, а вот тем, кто использует CodeIgniter, долго будут сниться кошмары о «возвращении к PHP 4».
Ссылка $this как бы намекает, что используется PHP 4-подход, в то время как статические методы характерны для PHP 5.
$this всегда обращается к «текущему» объекту, и точно не стоит использовать ее для доступа к глобальному коду.
$this->request->input->get() может выглядеть как удлиненная форма CodeIgniter-синтаксиса, но на самом деле мы просто находимся в контроллере. Когда контроллер создает экземпляр нового вложенного в него запроса, конструктор запроса также получает экземпляр на входе.
Если вы находитесь в модели или другом классе, то доступ вида $this->request->input->foo() не будет работать, потому что $this — не контроллер.
Статические методы — не панацея
Многие люди привязаны к статическим методам, и порой трудно их переубедить. Например, за них активно выступают FuelPHP 2.0 и Laravel 4.0 с реализацией слоя «Фасад» ( подробности в рецензии — how the Facade will work in Laravel 4).
Конструкция Input::get(‘foo’) создает фасад для экземпляров логики в фоновом режиме. Но это не решает вопросов, связанных с работой глобального кода. Самые ленивые при тестировании приложений могут переключаться между двумя режимами без необходимости полностью использовать новый фреймворк.
Есть отличное видео от Тейлора Отвелла (creator или laravel 4), в котором он описывает, как вы можете заменить статический код с единичным экземпляром, проверяемым через его DiC-контейнер.
Laravel 4 — IoC Controller Injection & Unit Testing from UserScape on Vimeo.
Это отличная презентация того, как можно обойтись без использования статических методов в Laravel. Хотя некоторые современные фреймворки, на первый взгляд, очень напоминают Kohana, они абсолютно по-разному решают даже самые стандартные задачи.
На этой печальной ноте…
Сейчас я занимаюсь преобразованием PyroCMS с CodeIgniter на Laravel. Пытаюсь перейти прямо от глобального кода PHP 4 к совершенному внедрению зависимостей — это абсолютное самоубийство. Промежуточный шаг перед использованием загрузчика CI — использование PHP 5, автозагружаемого кода PSR-2 с кучей статичных методов. Ну а пока мы все еще находимся в CodeIgniter.
Переход от статики к DiC-коду можно будет легко показать, когда мы, наконец, сделаем переход на Laravel.
Переход от сильносвязанного кода CodeIgniter к тестируемому PSR-2 — главная задача. Команда Pyro уже в пути — и это будет эпично.