Zend Framework советы и трюки

Статьи -> Программирование -> Zend Framework

Zend Framework советы и трюки

v:1.0 10.02.2010

Перевод статьи Zend Framework tips and tricks.
автор: Juozas devBlog

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

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

Отделяйте логику

Это утверждение наиболее очевидно, однако, поверьте мне, я находил ошибки в каждом проекте, в котором участвовал (более чем 10 с Zend Framework за последние полгода).
Если это контроллер, в нем не должно быть бизнес-логики, если это модель, в ней не должно быть обработки POST параметров и т.д.
Логика должна быть на своем месте и должна быть отделена от форм, bootstrap'а, представлений, помощников и т.д.

Перенесите всю логику из контроллера в модель или сервис (service). Используйте форму только для проверки и фильтрации данных, не обрабатывайте в формах данные.
Скрывайте сессии и идентификацию пользователей, выполняйте все необходимые операции в одном месте и предоставляйте API-функции для использования в других частях проекта.
Я могу продолжать и продолжать, однако надеюсь, что идея становится понятной. В конце-концов Вы поймете, что что-то не то, когда начнете тестировать код: когда чтобы всего лишь протестировать форму, Вам придется настроить frontController, request, cookie и почтовый сервер.

Глобальные переменные

Если Вы еще не видели это видео, посмотрите, пожалуйста, прямо сейчас, не пожалеете.
Глобальные переменные создают множество проблем при тестировании и противоречат концепциям Объекто-Ориентированного Программирования. Это касается получения значений $_SERVER, $_SESSION и т.д., все эти значения доступны через методы объектов запроса (посмотрите Zend_Controller_Request_Http) или отдельные классы, например Zend_Session.

И опять я хочу упомянуть о легкости тестирования, поскольку это то, о чем Вы постоянно должны помнить, разрабатывая программу. Тест не должен модифицировать глобальные переменные. Для получения значения тест должен пользоваться методами объектов, которые возвращают требуемые значения (например IP). Zend Framework предоставляет очень удобные классы для доступа ко всем глобальным переменным, грех ими не пользоваться.

Пользуйтесь значениями формы, а не запроса

Этой рекомендации очень легко следовать.
Посмотрите на следующий пример кода:

$form = new Form();
if ($this->_request->isPost()) 
{
 if ($form->isValid($this->_request->getPost())
 {
  $model = new Model($this->_request->getPost());
  $model->save();
 }
 else
 {
  $form->populate($this->_request->getPost());
 }
}

После того как форма проверена (а значит и значения отфильтрованы), все равно используются сырые данные запроса $this->_request->getPost(). Вы просто теряете многие интересные функции Zend_Form, например, игнорируемые элементы (кнопки "submit"). Более того, форма не использует фильтры, а Вы ведь настраиваете фильтры, не так ли? Кроме того, я могу передать в модель что угодно, и модель сама должна выполнить проверки данных. А значит в методе $form->getValues() должен быть реализован не только функционал проверок, но и фильтров.

В этом примере чрезмерно используется метод формы populate(). Этот метод разработан для установки первоначальных значений формы. В случае ошибки метод isValid() сам установит нужные значения, поэтому в дополнительной функции для установки значений нет нужды.

Не используйте exit()/die()

Первое, что я делаю, это удаляю все вызовы exit() и переделываю их с использованием исключений или выражения return. Существует очень мало случаев, когда использование одной их этих функций можно считать оправданным. Для примера давайте рассмотрим такой код действия контроллера:

if (!$this->userHasPermissions())
{
 $this->_redirect('/');
}
$form = new Form_Add();
if (//submit form)
{
 // save with $form->getValues();
 $this->_redirect('/index');
 exit();
}
// какие-то другие действия

Первая проблема - думать, что $this->_redirect() вызовет exit() и таким образом выполнение действия будет закончено. Хотя это действительно так и есть, Вы должны избегать подобные случаи. Такие вызовы делают невозможным генерацию событий post*. Более того это делает тестирование невозможным или некорректным. Zend_Test отключает вызов exit() в помощниках контроллера, таким образом во время тестирования Вы не можете протестировать проверку прав. Чтобы исправить эту проблему, просто добавьте return перед выполнением перенаправления (return $this->_redirect(‘/’)) и все будет в порядке.

Более того, второй exit() абсолютно бесполезный и делает код не пригодным для тестирования. Чтобы исправить ситуацию, достаточно добавить return, это не даст выполнить последующий код, представление не будет перерисовано, т.к. помощник viewRenderer контролирует все перенаправления, и если обнаружит таковое, ничего не делает. Исходя из моего опыта, после сохранения данных формы, в код достаточно поместить только перенаправление, конечно без exit().

Используйте framework вместо PHP

По началу это может показаться немного странным, однако если Вы используете framework (в данном случае это Zend Framework), не начинайте переносить приемы и методы из приложения PHP пятилетней давности. Как, например, здесь (действие контроллера):

$object = new Some_Object();
$image = $object->generateImage();
 
header ('Content-type: image/jpeg');
echo $image;

Я даже и не знаю с чего тут начать... Вся эта логика уже вставлена в объект ответа (response), т.е. Вы можете сделать следующее:

$this->getResponse()->setHeader("Content-type", 'image/jpeg');
$this->getResponse()->setBody($image);

Эти два фрагмента могут показаться одинаковыми, но это не так. Вы можете в этом очень легко убедиться, код не работает с глобальными переменными (header() - это функция глобальной переменной) и обработка запроса не прерывается. Контроллер не выводит никакие данные (поэтому и не используется echo), он просто получает объект запроса и отправляет объект ответа, и это все. Вывод данных контроллером точно так же прерывает выполнение процесса как и вызов exit(), поэтому не забудьте убедиться, что вы не прервали этот поток.

И еще небольшие дополнения

В Application.ini описано свойство includePaths, которое используется для добавления дополнительных путей в переменную path. Хотя это и превосходно работает, я рекомендую не использовать эту возможность, т.к. эти пути добавляются всякий раз, когда вы создаете новый экземпляр приложения (это так в 1.9, но может измениться в будущем). Если Вы тестируете контроллеры, то наверняка всякий раз перед началом создаете новый экземпляр. Проделав сотню-другую тестов, Вы обнаружите, что быстродействие раз от раза все ниже и ниже.
Чтобы найти и исправить ошибку мне потребовалось несколько часов, я до сих пор все это помню.

Если Вы используете jQuery или другой помощник вида для javascript, пользуйтесь всеми его возможностями. Т.е. для добавления дополнительных ресурсов и кода используйте функции типа addJavascriptFile(), addJavascript(), addStylesheet(), addOnload() и т.д. Если Вы вставляете javascript непосредственно в представление, все будет работать замечательно, однако при использовании помощника вида весь код обязательно надо положить в одно место и не разбрасывать по разным местам.

Заключение

Это всего лишь небольшая часть тех проблем и задач, с которыми я столкнулся в своей практике, у меня есть еще, что рассказать. Надеюсь, что Вы тоже поделитесь своими секретами. Хочется верить, что я дал Вам несколько полезных идей как правильно работать с Zend framework, и Ваш код станет красивее, а время разработки сократится, поскольку все будет прозрачно и наилучшим образом организовано.

Петрелевич Сергей
petrelevich@yandex.ru
www.SmartyIT.ru

Метки: PHP   Web   Zend Framework  

Комментарии.

Внимание.
Комментировать могут только зарегистрированные пользователи.
Возможно использование следующих HTML тегов: <a>, <b>, <i>, <br>.

ZendMania 10.02.2010 21:50:37
+100, за ссылку на ZendFramework.ru. Очень полезно будет "тыкать" новичков в разделы этой статьи.
 
Яндекс цитирования Ðåéòèíã@Mail.ru Rambler's Top100