Пользователь
0,0
рейтинг
23 апреля 2011 в 03:28

Разработка → Silex — микрофреймворк от создателей Symfony2

Почти год назад я опубликовал статью о микрофреймворке под названием 'fat-free', написанном на PHP. Тогда этот фреймворк и сама статья вызвали некоторый интерес, поэтому я решил сделать обзор еще одного PHP микрофреймворка в стиле популярного Sinatra — Silex project.
image
Созданный в известной в РНР кругах Sensio Labs, не менее известным Fabien Potencier — автором одного из самых популярных на сегодня PHP фреймворков — Symfony, Silex является облегченной версией ожидаемого армией фанатов (к которым осмелюсь отнести и себя) Symfony2.

Для своей работы Silex использует ключевые компоненты Symfony2 в связке с несложной реализацией шаблона проектирования “Внедрение зависимостей” в виде сервис-контейнера Pimple, который позволяет максимально просто отделить логические части кода друг от друга — сделать их независимыми.

Как и у Symfony2 — у Silex интуитивно понятный API, что делает процесс разработки достаточно приятным и позволяет практически в несколько шагов добавлять свой функционал в сам фреймворк.


Пример приложения


Простейшее приложение на Silex выглядит так:

require_once __DIR__.'/silex.phar'; // *.phar - одно из новшеств стандартного дистрибутива PHP 5.3. Фактически, это исполняемый архив (помните *jar в Java?).

$app = new Silex\Application(); // Еще одно из важных нововведений в PHP 5.3 — пространства имен. В данной строчке мы создаем инстанс приложения.

$app->get('/hello/{name}', function($name) { // Одна из самых ключевых особенностей фреймворка — присваивание контроллеров конкретным роутам.
    return "Hello $name";
});

$app->run(); // Запуск приложения


Как видите — все очень просто. Если пользователь сделает GET запрос на /hello/{name} — выполнится код внутри функции замыкания.

Установка


Для работы фреймворка понадобится PHP версии не ниже 5.3 с установленными в php.ini

phar.readonly = Off
phar.require_hash = Off .

Установка фреймворка сводится к загрузке phar-архива и подключении его в нашем bootstrap файле (index.php), как показано в примере выше.
Стоит упомянуть, что все запросы нужно перенаправлять именно на этот файл.
Если Вы используете Apache — создайте .htaccess с таким содержимым в корневой директории, рядом с index.php:

<IfModule mod_rewrite.c>
RewriteEngine On
#RewriteBase /path/to/app
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]


Маршрутизация


Silex позволяет принимать маршруты неограниченной длины:

$app->get('/hello/awesome/pink/ponnies', function(){
...
});


В маршрутах можно использовать переменные:

$app->get('/hello/awesome/pink/{animal}', function($animal)  {
...
}); 


Неограниченное количество переменных:

$app->get('/hello/{impression}/{color}/{animal}', function($impression, $color, $animal) {
...
});


Запросы, конечно, могут быть и POST:

$app->post('/ponnies', function() use ($app) { // обратите внимание, что объект $app для дальнейшего использования в контроллере нужно передать внутрь замыкания
    $request = $app['request'];
	echo $request->get('ponny');
}


И PUT:

$app->put('/blog', function() {
    ...
}); 


И DELETE:

$app->delete('/blog', function() {
    ...
});


К каждому маршруту можно прицепить цепочку валидаторов:

$app->get('/blog/show/{postId}/{commentId}', function($postId, $commentId) {
    ...
})
->assert('postId', '\d+') // только цифры
->assert('commentId', '\d+'); // только цифры


А также присвоить название:

$app->get('/', function() {
    ...
})
->bind('homepage');

что пригодится для генерации ссылок на эти маршруты.

Перед и после каждого запроса можно исполнять произвольный код с помощью соответствующих before/after фильтров:

$app->before(function() {
    // перед
});

$app->after(function() {
    // после
});


Сервисы


Реализация “Внедрения зависимостей” в виде Pimple является достаточно простой и понятной.

Создаем новый инстанс приложения:

use Silex\Application;
$app = new Application();


и обращаемся к нему как к массиву, присваивая как обычные переменные:

$app['some_parameter'] = 'value';


так и уже привычные замыкания:

$app['some_service'] = function() {
    return new Service();
};


Для дальнейшего их использования, достаточно к ним обратиться как к элементам массива:

$service = $app['some_service'];


Если же сервис должен быть создан в едином экземпляре, используем метод share приложения:

$app['some_service'] = $app->share(function() {
    return new Service();
});


В таком случае $app['some_service'] будет создан только один раз при вызове, а при последующих вызовах будет возвращаться его инстанс.

Расширения


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

use Acme\DatabaseExtension;

$app = new Application();

$app->register(new DatabaseExtension(), array(
    'database.dsn'      => 'mysql:host=localhost;dbname=myapp',
    'database.user'     => 'root',
    'database.password' => 'secret_root_password',
));


Из стандартных расширений сейчас доступны:

  • MonologExtension — логгер
  • SessionExtension — управление сессиями
  • TwigExtension — шаблонизатор
  • UrlGeneratorExtension — генерация URL


На подходе — Doctrine2 и генератор админки.

И это только начало. Адаптация сторонних библиотек в качестве расширений для Silex достаточно несложная, поэтому как только образуется сообщество вокруг этого фреймворка — их станет много.

Итоги


Микрофреймворки всегда будут занимать прочное место в создании веб приложений с несложной структурой, а выход микрофреймворка, базирующегося на плечах такого гиганта, как Symfony2 — безусловно очень важное событие в мире PHP.

Сайт фреймворка: http://silex-project.org

Полезные ссылки:

Сайт Symfony2
Документация Phar
Внедрение зависимостей
Виталий @icegreenberry
карма
66,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

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

  • +4
    Спасибо, надо будет поковырять. Symfony всё же бывает излишним для простых проектов.
  • +1
    Здорово, хорошая демонстрация 5.3-стайла. Вот только как всегда, на большинстве шаред хостингах про РНР 5.3 можно забыть…
    • +3
      Насколько я заметил, качественные хостинг провайдеры поддержку 5.3 уже давно включили.
      • 0
        А вы со многими хостерами работали?
        • 0
          Это риторический вопрос? Если конкретный, то где-то с 10, не больше.
          • 0
            Конкретный вопрос, мне действительно интересно. Пока доводилось общаться только с хостингами, предоставленными клиентами, в основном что-то корпоративное, поддерживаемое клиентскими же силами и парой местных хостингов, ибо интересовал городской пиринг. Не могли бы подсказать пару приличных хостеров, у которых однозначно есть РНР 5.3 именно на shared'ных тарифах?
            • +1
              hostmonster например
            • 0
              www.diphost.ru/hosting/

              Пользуюсь уже год, полет нормальный. Одно но — дешевый тариф 5.3 не держит.
              • 0
                ООО «Дремучий лес», эльфийский язык… как-то, эээ… странно, что ли.
                • 0
                  Вам шашечки, или поехали? © =)
            • 0
              hostgator: php5.3, ssh и адекватная техподдержка на самых дешевых тарифах.
            • 0
              А что насчет крупных игроков российского рынка хостинг-услуг?
            • 0
              NetAngels.ru даёт настраивать версию php и набор расширений прямо из панели.
        • 0
          Мне тоже интересен этот список :)
      • 0
        Возьмите VPS и не парьтесь, стоит столько же, а профита больше.
        • 0
          VPS подразумевает бОлшьую квалификацию, расширение зоны ответственности. Хорошо если сайт чисто для себя или информационный, а если это сервис, оказывающий платные услуги и хранящий персональные данные клиентов?

          Понятно, что большинство разработчиков способны поднять, скажем, AMP на Linux по ssh «чтоб работало», но вот, например, закрыть доступ извне для рута и/или сделать защиту от брутфорса требует уже более специфических знаний. Также как оптимальные настройки того же LAMP. Хостинг же предполагает, что его администраторы более квалифицированы и в обеспечении безопасности, и в тюнинге среды выполнения приложения, да и работают 24/7, а не 8/5.
    • +2
      Вы все-еще работаете с хостерами, которые на протяжении 2ух лет не могут обновить ведущую технологию?
  • +1
    Не знал о такой штуке. И вправду очень похожа на Sinatra. На PHP 5.3 конечно красиво всё получается.
  • 0
    На офф. сайте примеры немного хромают.
    $blogPosts = array(
        1 => array(
            'date'      => '2011-03-29',
            'author'    => 'igorw',
            'title'     => 'Using Silex',
            'body'      => '...',
        ),
    );
    
    $app->get('/blog', function() use ($blogPosts) {
        $output = '';
        foreach ($blogPosts as $post) {
            $output .= $post['title'];
            $output .= '<br />';
        }
    
        return $output;
    });
    

    Во-первых, данные блога получаются ещё до того, как мы узнали, что запрашивается действительно блог, а во вторых $output .= '
    '; немного перебор.
    Это я к тому, любопытно, как рекомендуется этот самый вывод организовывать, если по правильному? Twig подключать?
    • 0
      require_once "views/template.php"; пойдет? Понятие «по-правильному» вы определяете для себя сами, исходя из требований разрабатываемого приложения.
    • +2
      Сделайте что-то вроде
      function render($template, array $data) {
        foreach ($data as $key => $value) {
          $$key = $value;
        ob_start();
        require __DIR__ . '/../templates/' . $template;
        return ob_get_clean();
      }
      
      и пишите что-то вроде
      $app->get('/blog', function() use ($blogPosts) {
        $posts = $blogPosts; // тут может быть формирование массива из БД
        return render('../templates/blog.php', array('posts' => $posts));
      });
      , где templates/blog.php что-то вроде
      <?php foreach ($posts as $post): ?>
        <?php echo $post['title'] ?></br>
      <?php endfor ?>
      

      если не хотите Twig, Smarty или что-то ещё прикручивать. Хотя, по-моему, в большинстве случаев Twig лучше чем native PHP
      • 0
        На всякий случай
        Вместо foreach ... $$key = $value; удобнее использовать функцию extract.
  • +2
    Красиво выглядит. Сразу назрело пару вопросо:
    — замыкания с hello world конечно хороши, а что делать если ножа что- то побольше? Станет не так красиво.
    — неограниченный путь и колко параметров, а в каком фреймворке оно ограничено?
    • 0
      В момент, когда станет совсем некрасиво, разработчику стоит задуматься о переезде на полновесный фрэймворк. Silex не создавался для разработки комплексных интернет-магазинов и социальных сетей — для этого есть Symfony2.
      • +2
        И какой кровью ему придется «переезжать»?
        • +4
          А что, вы уже собрались писать гигантский проект с сотней контроллеров и десятком бизнесс-объектов на Silex?

          Если вы написали домашнюю страничку, а потом, вдруг, по мановению волшебной палочки решили сделать из него социальную сеть — вам в любом случае придется пересмотреть архитектуру контроллеров и роутинга. Но правильно спроектированные слои бизнесс-логики и представления могут переехать неизменными. О чем вопрос вообще?
        • +1
          И все сервисы в Silex — простые PHP объекты, создаваемые через DIC. Переехать куда угодно когда угодно — не проблема.
    • 0
      Не только замыкания можно использовать, но и любую callable, как я понял.
  • 0
    Интересный фреймворк. Очень радует, что стали активно использовать phar.
  • 0
    DoctrineExtension уже в репозитории.
    • 0
      Только DBAL. ORM там не будет: github.com/fabpot/Silex/pull/25#issuecomment-1010565.
  • +2
    Я если честно не очень понял как компоновать приложение использую этот фреймворк?
    Не в один же файл все запихивать?
    • +2
      Про Silex не скажу, но если он равняется на Sinatra — легко можно организовать подобие MVC.

      <offtоp>
      Лично для меня Синатра выглядит симпатичней все-же, не холивара ради :-)
      
      require 'sinatra'
      get '/hi' do
        "Hey there!"
      end
      

      </offtоp>
      • +2
        А в «этих ваших синатрах» тоже всё в один большой файл засовывается?
        • 0
          Извините, но вопрос не совсем понятен :-) Что значит «в один большой файл»? VC есть из коробки (вьюхи находятся в отдельных файлах, все изящно и красиво, можно использовать HAML. А насчет M — можно добавить ORM (DataMapper как отличный пример), отделить логику модели от контроллера… вот и получаем MVC. Но имхо все-таки Синатра больше подходит для маленьких проектов, для больших можно посмотреть в сторону Rails, там намного больше вещей «из коробки».
          • 0
            Он наверное имел ввиду, что все «контроллеры» придется все пихать в один index.php. Или как? Поправьте…
            • 0
              require 'lib/file-with-my-stuff'

              Или имеются ввиду роуты?
        • 0
          Я все делаю отдельно. Модели отдельно, нэимспэйсы (я использую экстеншен) каждый в своем файле, хелперы отдельно, вьюхи отдельно. в init.rb только конфигурация и загрузка остальных файлов.
        • 0
          Каждый роут можно обрабатывать в отдельном файле а в главном (index.php) собрать их все вместе.
    • 0
      Прелесть таких микрофреймворков в том, что они не ограничивают фантазию, т.е. выбор способа компоновки за вами.
    • 0
      It's up to developer. Как всегда, вообщем. Кто мешает разбить этот один файл на reusable controller groups: http://silex-project.org/doc/usage.html#reusing-applications или, допустим, вынести шаблоны в отдельный layer? Всего 1 require и у вас уже 2 файла. В чем проблема?
    • 0
      1) банальные require/include в любом удобном месте
      2) в качестве контроллера, как я понял, можно использовать любую callable, в т. ч. методы классов/объектов (Autoload идёт в комплекте)
      3) $app->mount позволяет собирать приложение из других приложений по префиксу, то есть если уже есть приложение (экземпляр Silex\Application) $blog, обрабатывающее GET /posts, GET /posts/{id}, POST /posts, PUT /posts/id, то с помощью $app->mount('/blog', $blog), мы привяжем его к GET /blog/posts и т. д.
  • 0
    Хмм, смотрю, Sinatra, WebMatrix, Silex — видимо, популярность микро-фреймворков растет на каждой платформе.

    В них круто то, что они и заявляются как «очень простые», там нет никакого «over-engineering» и народ не пытается раздуть из них что-то на все случаи жизни.
    • +2
      Так а для каких целей они применимы? Я вот не пойму, где можно такое использовать
      • 0
        Идеальный вариант — прототипирование для последующего перехода на более «взрослые» фреймворки. Ну и для действительно небольших проектов (а точнее — для простых в плане логики).

        Плюс — отличная вещь для начинающих разработчиков, чтобы не забивать голову сразу всем.
      • 0
        Блог, сайт компании, сайт проекта. Вообщем вся мелочь, что сейчас за уши притягивается быть написанным на полновесном фрэймворке, после чего люди тонут в рутине фрэймворка, вместо решения реальных бизнесс-задач.
      • 0
        Или там где не хочется писать тот же REST роутинг с нуля (а для python/ruby чуть ли не веб-сервер с нуля надо писать), или там где full stack фреймворки слишком жёстко ограничивают, привязываясь к большой иерархии классов, не позволяя малой кровью сменить шаблонизатор, ORM и т. п., ну или просто слишком излишни/громоздки.
      • 0
        Сайты фотографов, портфолио, музыкальных групп. Да, у каждой уважающей себя группы есть сайт. Вот на народе миллионы сайтов — все они потенциально могут быть повешены на минифреймворк, что даст им интерактивности, которой нельзя добиться без серверного языка. А по сравнению с голым пхп оно будет смотреться опрятнее, а главное — будут обойдены многие грабли, с которыми иначе придётся столкнуться самому.
      • 0
        Для простых по структуре веб-сайтов с небольшим количеством роутов. Это не обязательно сайты-визитки. Простым по структуре можно считать, например, сервис микроблогов — всего несколько роутов. Или видеохостинг — то же самое.
        При этом нагрузки на такие сайты обычно достаточно высокие.
        • 0
          Количество роутов по-моему не принципиально, если их все в один файл не заносить.
  • 0
    Мне еще очень понравился gluephp.
    Задача у него одна — роутинг.
    Привязка URLов идёт к классам.
    
        require_once('glue.php');
    
        $urls = array(
            '/' => 'index',
            '/(\d+)' => 'index'
        );
    
        class index {
            function GET($matches) {
                if ($matches[1]) {
                    echo "The magic number is: " . $matches[1];
                } else {
                    echo "You did not enter a number.";
                }
            }
        }
    
        glue::stick($urls);
    

    Недостаток для меня один — он больше ничего не умеет и нет возможности расширения (у разработчиков другое мнение, они заложили в основу принцип — «Do one job and do it well»).
    • 0
      Там нечего расширять, ибо это не фрэймворк ни разу. Это простейшая, искуственно-ограниченная имплементация роутера.
      • 0
        Вопрос терминологии.
        Сами они называют своё творение микрофреймворком, о чём и говорят на главной — «Glue is a PHP micro-framework.».
        С таким же успехом можно сказать что Silex тоже ни разу не фреймворк а просто реализация роутинга и неких «сервисов».
        • +1
          — GluePHP = routing (proof)
          — Silex = routing + HTTP abstraction layer + exception handler + event manager + service container + extensions manager (proof)

          Терминология тут не при чем.
        • 0
          Ну и если уж говорить о терминологии:
          «В отличие от библиотек, которые объединяют набор подпрограмм близкой функциональности, фрэймворк содержит в себе большое количество разных по назначению библиотек.» (from wikipedia).

          GluePHP = роутер = один сервис = НЕ фрэймворк, а роутер
          Silex = набор библиотек с service container'ом = много сервисов = фрэймворк
    • 0
      ох лол, не ожидал, что он действительно микро… один класс с одной функцией.
  • 0
    Doctirne2 там не будет: github.com/fabpot/Silex/pull/25#issuecomment-1010565. По крайней мере в виде оффициального экстеншена. Он там и не нужен!
    • 0
      *Doctrine2. Извиняюсь за опечатку.
  • 0
    Как по мне — лучше от таких «изваротов» разработчику не станет.

    Реализовать привычный MVC можно в 45 киллобайтном PHP файле (пример code.google.com/p/green-framework/source/browse/trunk/system/Green.php). Зато затем можно будет легко портировать код под, например, CodeIgnitor или Kohana.
    • 0
      Ну примерно одну функцию выполняют да и, кажется, похожим способом. Только Silex даёт большую гибкость — использовать в качестве контроллеров, моделей и вью можно всё что угодно, ник чему не привязываясь (кроме роутинга). Ну и плюс REST фактически из коробки.
      • 0
        Вообщем то согласен. Для написания разного рода сервисов на базе REST этот фреймверк подходит неплохо.
    • 0
      В основе Silex лежит service container. Все ваши и корневые сервисы являются простыми PHP объектами, не завязанными на сам фрэймворк. Можете переезжать хоть на друпал в любой момент.
  • –2
    Как только народ не изголяется, только бы рельсы не учить!
    • +1
      Казалось бы, причём тут рельсы в блоге о php-фрэймворке, не говоря о том, что symfony2 во многом рельсам не уступает, а в чём-то и превосходит…
      • +1
        Видели пантеру с гирей на хвосте?

        Все эти нано-фреймворки с разной степенью успешности хотят (и стремятся) быть рельсами, но гиря на хвосте (в виде многословности php и непопулярности php reflections) ограничивает высоту прыжка
        • 0
          В том-то и дело что «стремятся быть рельсами» не мини-фреймворки (Synatra же не стремиться стать рельсами), а у фулл-стэк получается ими быть хорошо, а в чём-то и лучше. Какой gem реализует паттерны DataMapper и UnitOfWork? То, что в руби гуглится по DataMapper, то только одно название, а по сути ActiveRecord.
  • 0
    Товарищи, а есть что нибудь вроде сайлекса., такое же развитОе, но для наших реалий? хостинг php 5.2+
  • 0
    может кому-нибудь сэкономит пару минут:
    в ubuntu 11.04 столкнулся с тем, что пришлось дописать suhosin.executor.include.whitelist = phar в suhosin.ini

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.