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
    Внедрение зависимостей
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 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
                                                                  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

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