Phalcon — самый быстрый PHP MVC Framework

от автора


Создание скомпилированных MVC фреймворков для PHP не раз приходила на ум кодерам.

Достоинства такого подхода:

  • Высокая производительность
  • Малая нагрузка файловой системы
  • Меньший расход памяти (при строгой типизированности)
  • Частичная обработка данных без интерпритации

И само собой не менее явные недостатки:

  • Если Вы не знаете C, то Вы полностью зависите от разработчиков
  • Проект может в любую секунду сдуться
  • В зависимости от архитектуры, часть модулей все равно приходится писать самому, что уменьшает выигрыш

В этой статье я попытаюсь познакомить с еще одной попыткой сделать скомпилированный PHP MVC Framework.

Знакомство

Сам я в поисках быстрого, надежного и способного фреймворка. Гуляя по зарубежным форумам и блогам, наткнулся на интересный бенчмарк, где некий фреймворк на «Hello World!» уделывал пузатых знаменитостей в несколько раз.

Пройти мимо такого я не смог и принялся узнавать, как это работает и развивается.
Проекту менее года. Первый коммит на github — 10 января 2012. И да, это open source проект. Насколько я понял, сейчас им более менее активно занимаются 3 человека.

Авторы пытаются дать возможность людям писать код, не задумываясь о его производительности, придерживаясь стандартов и давая доступ к большинству используемых методов, которые загружаются в память со стартом сервера.

Пример

Лучший способ изучить framework — сделать что-нибудь на нем, параллельно изучая документацию.
Я сделал 3-х страничное приложение, показывающее некоторые возможности phalcon, а именно:

  • Роутинг
  • Работа с БД, на внутреннем языке PHQL
  • Работа с events
  • Фильтрация данных
  • Кеширование
  • DI (dependency injection)
  • Возможности встроенного движка шаблонов Volt

Кроме того, разработчики заявляют гораздо большее:

  • ODM — работа с документо-ориентированными БД
  • Многоязычность
  • Автоматическое создание приложений CRUD из консоли или веб-морды
  • Поддержка нескольких популярных движков шаблонов
  • Микро приложения (для создания REST API)
  • Создание логгера любой конфигурации
  • Создание своего event manager с fire и catch
  • Встроенный обработчик html тегов для шаблонов
  • Поддержка nemespace и мульти-модульности
  • Обработка сессий и flash сообщений
  • ACL
Иерархия проекта:

 xmpl/     apps/         app/config/         app/controllers/         app/models/         app/views/         app/My/     public/         public/img/         public/css/         public/js/ 

Весь код будет лежать по пути /apps/, инициализация приложения /public/index.php. На последний файл собственно и нужно настроить редирект несуществующих страниц, через apache (.htaccess в папках / и /public/ ) или nginx.

Инициализация:

Про инициализацию вкратце под спойлером.

<?php  //загружаем конфигурационные данные из ini файла $config = new Phalcon\Config\Adapter\Ini( '../apps/config/config.ini' );  //Подключаем загрузчик, показывая ему, где будут лежать вызываемые классы $loader = new \Phalcon\Loader(); $loader->registerDirs(array( 	$config->application->controllersDir, 	$config->application->modelsDir, 	$config->application->myDir, )); $loader->register();  //Подкючаем DI $di = new \Phalcon\DI();  //Компонент, отвечающий за обработку url. $di->set('url', function() use ($config){ 	$url = new \Phalcon\Mvc\Url(); 	return $url; });  //Подключаем модель соединения с БД, доступны ( Mysql, PostgreSQL, SQLite) $di->set('db', function() use ($config) {     $connection = new \Phalcon\Db\Adapter\Pdo\Mysql(array(         "host" => $config->database->host,         "username" => $config->database->username,         "password" => $config->database->password,         "dbname" => $config->database->name     ));      return $connection; });  //2 вспомогательных компонента для работы с БД $di->set('modelsManager', function(){ 	return new Phalcon\Mvc\Model\Manager(); }); //Указываем, где хранится мета-данным из БД, доступны (Apc, Files, Memory, Session) $di->set('modelsMetadata', function(){ 	return new \Phalcon\Mvc\Model\Metadata\Memory(); });  //Подключаем роутер $di->set('router', 'Phalcon\Mvc\Router');	  //Подключаем диспетчер, чтобы иметь доступ к методам view из контроллера. Можно назначить свой обработчик. $di->set('dispatcher', function() use ($di) { 	$dispatcher = new Phalcon\Mvc\Dispatcher(); 	return $dispatcher; });  //Обработка ответов и запросов $di->set('response', 'Phalcon\Http\Response'); $di->set('request', 'Phalcon\Http\Request');  //Подключение фильтра данных $di->set('filter', function(){     return new \Phalcon\Filter(); });  //Подключаем сервис внутреннего движка Volt с настройками $di->set('voltService', function($view, $di) use ($config) {     $volt = new Phalcon\Mvc\View\Engine\Volt($view, $di);     $volt->setOptions(array(         "compiledPath" => $config->application->templCompDir,         "compiledExtension" => ".compiled"     ));     return $volt; });  //Подключаем компонент, отвечающий за вид. Также назначаем уме eventManager,  //который, получает несколько событий выбрасываемых view. Таким образом мы  //можем манипулировать с шаблонами как захотим $di->set('view', function() use ($config) {      $eventsManager = new \Phalcon\Events\Manager();     $viewManager = new ViewManager();     $eventsManager->attach('view', $viewManager);      $view = new \Phalcon\Mvc\View();     $view->setViewsDir( $config->application->viewsDir );     $view->registerEngines(array(     	".phtml" => 'voltService'     ));      $view->setEventsManager($eventsManager);      return $view; });  //Подключаем фронт и бакенд кеширование, доступны front (Base64, Data, None, Output) и backend (Apc, File, Memcache, Mongo), само собой, можно дописать и свои $di->set('cache', function(){      $frontCache = new Phalcon\Cache\Frontend\Data(array(         "lifetime" => 60     ));      $cache = new Phalcon\Cache\Backend\Apc($frontCache);     return $cache; });   //собственно инициализация и вывод ошибок как есть на экран try { 	$application = new \Phalcon\Mvc\Application(); 	$application->setDI($di); 	echo $application->handle()->getContent(); } catch(Phalcon\Exception $e){ 	echo $e->getMessage(); } 

Большую часть можно подключить автоматически, вот так:

$di = new Phalcon\DI\FactoryDefault(); 
Контроллеры и свои классы:

Теперь, в Вашем приложении доступен стандартный роутинг /baseUri/ControllerName/ActionName/, подключены методы, которые через di наследуют контроллеры $this->cache, $this->dispatcher, $this->db

Также Вы можете вызывать свои классы, находящиеся в папке /apps/My/
Класс ViewManager получит все события, генерируемые View. На интересует beforeRender. В нем, мы передадим в вид переменные, содержащие название класса и действия.

Также мы создадим класс BaseController

class BaseController extends \Phalcon\Mvc\Controller { 	public function initialize()     {         Phalcon\Tag::prependTitle('Example | ');     } } 

class IndexController extends BaseController {  	public function initialize()     {         //Устанавливаем текст в тег title, также можно добавлять постфикс (сделано в контроллере Poll)         Phalcon\Tag::setTitle('Index');         parent::initialize();     }      public function indexAction(){      } } 

Он наследует стандартный класс. Наши контроллеры, будут уже наследовать BaseController и получать префикс к html тегу title.

View

Phalcon предоставляет довольно удобный метод шаблонов, где существует иерархия.
Шаблоны хранятся в папке /apps/views/
Корневой шаблон /apps/views/index.phtm рендерится всеми контроллерами, кроме тех, где явно задан другой путь.
Этот файл может содержать в себе дальнейший путь иерархии:

{{ content() }} 

Я использовал синтаксис встроенного движка шаблонов. Для других движков тоже есть свои аналоги.
Эта функция вызывает следующий шаблон, расположенный по пути:
/apps/view/layer/ControllerName.phtml

По сути, задавая особое оформление для определенного контроллера, как я и сделал в своем приложении. В нем также можно вызвать content(), тем самым подгрузив шаблон /apps/views/ControllerName/ActionName.phtml

В шаблонах можно подгружать другие шаблоны, заменять предустановленные блоки, вызывать пользовательские и предопределенные движком функции, обращаться к методам Models.
Только Volt их молодой проект, поэтому многих функций в нем нет, но они запланированы на ближайшие релизы.
Из коробки, поддерживают Slim, Smarty, Mustache

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

Модели

Подключение к БД, осуществляется с помощью PDO. Имеется 2 реализации работы с базой данных, объектно-ориентированный путь и PHQL, свой обработчик псевдо SQL строк.
К сожалению, первый подходит только для довольно простых запросов, а второй будет сложным, для тех, кто привык к первому.

Модель в приложении

class Poll extends Phalcon\Mvc\Model {     //объявление используемых переменных в строках, явное указание, какие доступны напрямую public     public $id;     public $gender;     public $age;     public $read_modern;     public $authors;     public $genre;     public $method;     public $timestamp;      //метод вызывается при инициализации БД, должен возвращать имя используемой таблицы     public function getSource()     {         return 'answers';     }      //выбор метода соединения при инициализации     public function initialize()     {         $this->setConnectionService('db');     } } 

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

Недостатки

Я не до конца разобрался во всем, что может этот фреймворк, но все же заметил недостатки:

  • У меня так и не получилось собрать dll под windows. Разработчики так и не ответили.
  • На vps не смог собрать версию 0.6.1, сообщал разработчикам, так и не смогли разобраться.
  • Не нашел способа настроить роутинг для статичного файла example.com/tp/score.json Файла нет — роутер к контроллеру и методу, иначе статичный файл. Буду разбираться.
  • Очень мало возможностей у встроенного шаблонизатора Volt.
  • Не нашел способа вывода Flash сообщений без использования сессий, не отключая рендеринг.
  • Сильно разбитая документации по моделям — 3 отдельных раздела, нет структурности.

Трудно назвать это недостатками. Разве что нет прямого общения с разработчиками, кроме issue list на гитхабе.

Функционал приложения

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

Железо: VPS хостинг. Процессор х1 500 МГц, ОП 256 Мб. Лошадка слабая.
Подключен APC. Настройки все дефолтные. Сервер: Nginx — PHP-FPM — PHP — MySQL

Синтетические тесты:
1. -c50 -d5 -r10
2. -c100 -d2 -r10
3. -c300 -d2 -r20 (LA — 0.7)
4. -c400 -d1 -r20 (LA — 0.47)
5. -c800 -d1 -r30 (LA — 1.1)
6. -c1000 -b -r20 (LA — 2)
(-с: конкуренты, -d: задержка перед повторным вызовом, -r: количество повторений, -b: вызов без задержки, LA: load average)

Siege делает в рандомном порядке 3 запроса, все динамические. 2 из них с запросами к БД, с кешированием в 1 минуту.
При большой конкурентности появились ошибки (до 2% запросов).
Максимально обрабатывал 516 запросов в секунду. Довольно недурно. Если хранить запрашиваемые json в файлах и обновлять их по cron, то можно нагрузку в разы сократить.

Ссылки

Сайт Phalcon
Репозиторий Phalcon

Работающий пример
Исходники примера на GitHub

P.S.

Опрос в приложении не просто так выбран 😉
И извиняюсь за сумбур, в одной статье выложить все невозможно.

ссылка на оригинал статьи http://habrahabr.ru/post/159217/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *