Создание скомпилированных 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. В нем, мы передадим в вид переменные, содержащие название класса и действия.
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/
Добавить комментарий