Как реанимировать ваш PHP-проект с помощью Symfony2 компонентов

Автор оригинала: Xavier Lacot
  • Перевод
Данный пост является переводом не статьи, как принято, а доклада+презентации, поэтому текст поста достаточно вольный.

Думаю, всем хорошо известно и очевидно, что PHP — один из самых популярных языков программирования, на котором написано множество веб-проектов, начиная с персональных homepage-страниц и заканчивая мастодонтами типа Facebook, Vimeo, WordPress и даже YouPorn.

PHP появился в 1995 году, при этом полноценная поддержка ООП была реализована только в PHP5, который вышел в 2005 году. За это время было написано большое количество кода, как хорошего, так и плохого, а точнее сказать сильно устаревшего и тяжело сопровождаемого.

Многие проекты, как и экосистема PHP в целом, к настоящему моменту стали представлять подобие оживленного городского квартала.



Новые версии PHP


Новое десятилетие принесло нам PHP5.3 и PHP5.4, которые помимо увеличения производительности несут в себе множество плюшек! Вот только некоторые из них:

1. Пространства имен (php 5.3)

namespace JoliCode\Conferences;
use General\Talk\Session;

class SymfonyLive extends Session
{
    public function runPresentation()
    {
    } 
}

  • Спасают от совпадений в именовании классов;
  • Снижают неопределенность;
  • Уход от длинных именований классов.

2. Анонимные функции и замыкания (php 5.3), и даже внутри объектов (php 5.4)

$container['session'] = function ($c) {
    return new Session($c['session_storage']);
};

3. Phar-архивы (php 5.3)

Позволяют распространять библиотеки в виде одного подключаемого phar-файла.

4. «goto» — что за на..?? (php 5.3)

5. Трейты (php 5.4)

6. Короткий синтаксис объявления массивов! (php 5.4)

function fruits() {
  return ['apple', 'banana', 'orange'];
}

echo fruits()[0]; // Outputs: apple


и много чего другого.

Фреймворки


Новые версии PHP стали катализатором появления фреймворков. Среди них стоит упомянуть symfony, Zend Framework, Yii, CodeIgniter, CakePHP. Почти всех из них были значительно обновлены в вышедших вторых версиях.

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

Стратегия реанимации проекта


Представим, что ваш проект существует уже 5 лет. За это время:

  • Было реализовано большое количество функциональности;
  • Проект работает в production;
  • Его постоянно использует большая аудитория пользователей;
  • Скопилось больше количество данных;
  • Вокруг проекта сформировалась опытная команда.

При этом:

  • Медленно происходит внедрение новой функциональности;
  • Проблема с сопровождением проекта и его инфраструктурой;
  • Тяжело поддается улучшению существующая функциональность.



Путь 1: Большой взрыв

Наиболее естественное желание в такой ситуации — выкинуть весь код и переписать заново! Представим, что мы пошли по такому пути. Несомненно, мы получим удовлетворение от возможности работы с одним из новых современных фреймворком, забыв про старый код, а местами быдлокод, как страшный сон.

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

Путь 2: Будь последовательным

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

Переходим к действию


Шаг 1. Переводим проект на PHP 5.3 или PHP 5.4



Для начала обновляем PHP как минимум до версии PHP 5.3. Делаем это аккуратно, выполним обновление сначала на dev-сервере и проверив, что никакие части системы не отвалились. Затем можно проверить на prod-сервере. При этом желательно это делать не на всем проекте, а в режиме A/B-тестирования, так, чтобы на новую среду попадала только часть пользователей.

Как только вы убедились, что все работает нормально, можно двигаться дальше.

Шаг 2. Готовим фундамент под будущий рефакторинг системы



Подключаем ключевые компоненты: ClassLoader, DependencyInjection и HTTPFoundation. Они помогут нам с рефакторингом и будут фундаментом для подключения новых компонентов.

Эти и все подследующие компоненты можно легко подключить с помощью пакетного менеджера Composer. Он позволяет лаконично описывать зависимости проекта от сторонних библиотек в json-формате, автоматически устанавливать и обновлять их, а также генерировать autoload-файл для их подключения в проекте. На Хабре есть хорошая статья о том, как его использовать.

В нашем случае конфигурационный файл для Composer будет выглядеть так:

{
    "autoload": {
        "psr-0": {}
    },
    "name": "xavierlacot/blog",
    "description": "My old blog on steroids",
    "require": {
        "php": ">=5.3.3",
        "symfony/class-loader": "2.1.*",
        "symfony/dependency-injection": "2.1.*",
        "symfony/http-foundation": "2.1.*"
    } 
}

Устанавливаем компоненты:

$ php composer.phar install
Installing dependencies from lock file
- Updating symfony/class-loader (dev-master)

И подключаем их в наш проект:

<?php
// подключаем сгенерированный менеджером Composer файл
require 'vendor/autoload.php';

Теперь мы можем их использовать!

ClassLoader. Стандарты автозагрузки классов

Полтора года назад сообществом PHP был принято несколько соглашений, одно из них, соглашение PSR-0, описывает правила и требования к коду для совместимости с современными автозагрузчиками классов (об истории автозагрузчиков хорошо написано тут и тут)

Если говорить кратко, то стандарт разрешает два тип именования классов:

Через namespace (современный подход)
class: Symfony\Component\HttpFoundation\Request
path: vendor/src/Symfony/Component/HttpFoundation/Request.php

Через подчеркивания (PEAR-стандарт, устаревший подход)
class: Twig_Extension_Core
path: vendor/twig/lib/Twig/Extension/Core.php

При этом автозагрузчик при подключении файла класса автоматически заменяет знак слеша (\) и подчеркивания (_) на разделитель директорий (/) добавляя расширение .php в конце.

Компонент ClassLoader позволяет организовать автозагрузку классов в соответствии с соглашением PSR-0.

Шаг 3. Рефакторинг классов и использование ClassLoader

Например, у нас есть некий класс для работы c LDAP:

<?php
class prefixedLdapConnector
{
    public function __construct()
    {
        // какой-то код
    } 
}

Приводим его к PSR-0 стандарту:

<?php
namespace Prefix\Ldap\Client;

class Client
{
    public function __construct()
    {
        // какой-то код
    } 
}

Регистрируем пространство верхнего уровня Prefix в ClassLoader:

use Symfony\Component\ClassLoader\UniversalClassLoader;

$loader = new UniversalClassLoader();
$loader->registerNamespace('Prefix', __DIR__ . '/src/');
$loader->register();

Теперь при использовании класса Prefix\Ldap\Client в вашем коде ClassLoader позаботится об его автоматической загрузке:

//здесь свою работу сделает ClassLoader
use Prefix\Ldap\Client;

$client = new Client();


Шаг 4. Рефакторинг обработки запросов/подготовки ответов. Использование HttpFoundation



Компонент HTTPFoundation упрощает обработку входящих запросов и подготовку ответа сервера.

Добавив в проект 2 строчки:

//здесь свою работу сделает компонент ClassLoader, подключив нужный класс
use Symfony\Component\HttpFoundation\Request;
//а здесь уже работает класс Request компонента HTTPFoundation
$request = Request::createFromGlobals();


мы получаем объект $request, который знает все о входящем запросе:

  • $request->request заменяет $_POST
  • $request->query заменяет $_GET
  • $request->cookies заменяет $_COOKIE
  • и т.д.


И аналогично с Response:

use Symfony\Component\HttpFoundation\Response;

$response = new Response();

$response->setContent('This will be the response content');
$response->headers->set('Content-Type', 'text/html');
$response->setStatusCode(200);

// отправка ответа Response
$response->prepare($request);
$response->send();


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

Шаг 5. Оформляем функциональность проекта в сервисы. Компонент Dependency Injection

Почти во всех проектах существует целый ряд функций, за которые отвечают разные библиотеки, классы или банально программные функции. Компонент Dependency Injection позволяет организовать и централизовать процесс создания и конфигурирования объектов, которые реализуют ту или иную функциональность. К таким объектам могут быть отнесены почтовая служба, менеджер по работе с БД, шаблонизатор и многие другие.



Допустим, у нас есть класс для отправки почтовых писем:

<?php
namespace Prefix\Mailer;

class Mailer
{
    $prefix = '';

    public function send($to, $subject, $body)
    {
        //отправка почты
    } 
}


И в нашем коде почта отправляется примерно так:

function saveUser($name, $email)
{
    $mailer = new Mailer();
    $mailer->send($user->getEmail(), 'Welcome ' . $user->getName(), 'A test');
}


Сделаем небольшой рефакторинг, создадим service-контейнер и зарегистрируем в нем наш почтовый класс:

use Symfony\Component\DependencyInjection\ContainerBuilder;

$container = new ContainerBuilder();
$container->register('mailer', 'Mailer');


Сделаем второй небольшой рефакторинг в строчках отправки письма:

function saveUser($name, $email)
{
    // stuff here
    $mailer = $this->container->get('mailer');
    $mailer->send($user->getEmail(), 'Welcome '.$user->getName(), 'A test');
}


Эти незначительные изменения дают сразу несколько бонусов:

  • Объект класса Mailer создается только один раз, даже если мы его получим из service-контейнера в другом месте проекта;
  • Сервис Mailer теперь можно централизованно конфигурировать;
  • Его легко заменить другим сервисом.


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

Шаг 6. Что дальше?

Подключив первые три компонента Symfony2, вы можете по тому же алгоритму начинать использовать другие не менее полезные компоненты:

  • Console — разработка консольных скриптов (вызываемые из командной строки или по cron)
  • Finder — поиск файлов и папок
  • Routing — позволяет задавать соответствие между HTTP-запросами и набором конфигурируемых параметров
  • Templating — обеспечит всем необходимым для работы с шаблонами в проекте
  • и другие.


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

Похожие публикации

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

    +9
    Удачи и приятного рефакторинга!

    Это, должно быть, шутка.
    Я по долгу службы как раз занимаюсь таким вот переписыванием по живому одного проекта. Это нечто. Поддержка того, что еще работает на старых скриптах, перевод на новые, поддержка старых и очень старых (а так же очень очень старых) данных, при изменяющихся требованиях к ним. Т.е. вчера формат номера телефона, например, был свободным, а сейчас к нему появилась кучка требований. Очень много мороки и очень мало видимого снаружи результата. В общем мало приятного совсем.
      0
      Еще и недокументированные костыли бывают…
        +7
        Недокументированные? Документации вообще нет никакой. Не думаю, что это редкость.
          +1
          как я вас понимаю…
        0
        Конечно, процесс рефакторинга непростой. Но я надеюсь, у вас и других коллег, кто столкнулся с такой задачей, все пройдет успешно!
        • НЛО прилетело и опубликовало эту надпись здесь
            +2
            Приятно или нет оценка всё же субъективная. Но могу вам рассказать ситуацию ещё похуже: нужно рефакторить код форка динамически развивающегося проекта, постоянно вбирая из оригинала новую функциональность, багфиксы и т. п., не имея никакого влияния на код оригинала.
            • НЛО прилетело и опубликовало эту надпись здесь
            +3
            отличная статья! пишите еще
              +2
              Вы, наверное, хотели сказать: «Переводите ещё» =)
                +1
                ну или так
              –1
              goto — новое оружие в руках быдлокодеров.
                +1
                goto — выше «добра» и «зла» ;)
                +2
                use Symfony\Component\DependencyInjection\ContainerBuilder;
                
                $container = new ContainerBuilder();
                $container->register('mailer', 'Mailer');
                


                И по сути отбрасываем всю простоту и легкость динамических языков и получаем Java, только ещё и раз в 30 медленней… И кто после этого быдлокодер?
                • НЛО прилетело и опубликовало эту надпись здесь
                    0
                    Хм… :)

                    $ find . | grep -E 'php|phtml|inc$' | wc -l
                    8071
                    
                    $ find . | grep -E 'php|phtml|inc$' | xargs cat | wc -l
                    1180995


                    И вроде как-то вполне неплохо себе без неймспейсов всё работает… Странно, да :)?
                    • НЛО прилетело и опубликовало эту надпись здесь
                        0
                        Количество точно не значит качество. Вот у вас в строчке, которой вы меряетесь, ошибка, напимер:
                        $ echo phphphphxxxxx | grep -E 'php|phtml|inc$'
                        phphphphxxxxx
                        
                          0
                          Вот у вас в строчке, которой вы меряетесь, ошибка:

                          Да, прошу прощения, действительно ошибся :). На результат это особо не влияет — вместо 8071 получается 8059 PHP-файлов…

                          Количество точно не значит качество.

                          Согласен. Более того, я считаю, что такое небольшое количество кода в Badoo говорит как раз о его высоком качестве.
                        0
                        Nginx + Varnish + Memcached


                        Казалось бы при чем тут PHP и Dependency Injection Container :)
                        На самом деле — нет. Не делают. Varnish и Memcached это уже оптимизация, а не средства из коробки. Не все проблемы скорости можно решить кешем. Для порталов — отличное решение, а для сервисов — Memcached и Varnish ничем не помогут.
                        • НЛО прилетело и опубликовало эту надпись здесь
                            0
                            Ну для 90% задач MySQL хватает. Он более универсален.

                            То есть я не знаю где учитывать Memcached. Его можно использовать для хранения сессия и для кеша. Но когда кешировать почти ничего не надо он тоже в скорости ничего не добавит. Максимум пару запросов для получения данных активного пользователя сохранит.

                            То есть да, на больших проектах, особенно в dev-режиме оно будет работать медленно. И это раздражает.
                        0
                        Преимущества динамических языков к развязыванию зависимостей отношения мало имеют и преимущества никуда не теряются.
                          –1
                          Почему же. Имеют. Самое прямое.
                          В Руби вот нету никаких Dependency Injection и DIC. И всё хорошо, все счастливы.

                          davybrion.com/blog/2010/10/why-you-dont-need-dependency-injection-in-ruby/
                            +1
                            Чтобы не быть голословным, вот как можно нормально реализовать Dependency Injection в PHP.
                            gist.github.com/1936860

                            Особенность этого подхода, в том, что мы вводим абстракции только когда они становятся необходимыми, а не изначально, когда в них смысла нет. Т.е. работает эволюционный подход.
                              0
                              Я вот только недавно узнал про такую штуку как DI, мол, это так круто и ZF2 и Symfony 2 его используют, и многие другие. А вы говорите что это плохо. И youROCK говорит что мы теряем простоту не жостко типизированного PHP.

                              И поэтому у меня вопрос.
                              А почему абстракции — это плохо? Усложняют понимание кода? Так вроде для того их и вводят, чтобы не знать о деталях. Вот из той статьи, где абстранции вводятся компилируя шаблоны — разве это проще? А когда будет не 3 класса, а 300 — конфиг будет, наверно, сложным.

                              Вот автор той статьи пишет: «When you develop you should not think on any injection or configuration». Вот разве мы думаем о том, какой там storage? У нас есть интерфейс и мы им пользуемся. Я не понимаю чем DI и DIC усложняют проект.
                                0
                                Сам по себе DI в PHP не обязательно реализовывать таким методом, который принят в Symfony, в том-то и прикол. На конференции РИТ++ в этом году был доклад про то, как делать нормальный и удобный DI в динамических на примере Perl, и вот там реализация была очень простая и удобная.

                                В PHP для реализации DI достаточно сделать что-то вроде следующего:

                                class Something
                                {
                                     protected $Model;
                                
                                    function __construct($model_class = 'Model')
                                    {
                                        $this->Model = new $model_class(...);
                                    }
                                
                                    function doSomething()
                                    {
                                         $this->Model->....;
                                    }
                                }
                                


                                Все эти конфиги, ямлы и многотонные «use Symfony\Component\DependencyInjection\ContainerBuilder;» слишком сложны и многословны, чтобы ими было легко и удобно пользоваться.
                            0
                            Польза DIC действительно крайне неочевидна. Ну кроме абстрактно-фабричных случаев.
                            Но вот остальные компоненты весьма годны.
                              +3
                              Когда у нас 20+ сервисов в проекте, они используются двумя способами:

                              1. В начале кода инициализации страниц подключаются и инициализируются все нужные библиотеки.

                              Плюсы
                              Примерно все в одном месте и их легко найти и конфигурировать.

                              Минусы
                              Каждая страница подключает все библиотеки.

                              2. Библиотеки подключаются и инициализуются в том месте, где используются.

                              Плюсы
                              Библиотеки подключаются тогда, когда нужно. Страницы быстрее инициализируются и требуют меньше памяти.

                              Минусы
                              * Инициализация разных сервисов в разных местах
                              * В разных участках кода может быть создано несколько экземпляров одного сервиса

                              В реальности часто оба подхода смешиваются, что еще больше все усугубляет. Тогда на помощь приходит DIC.
                              0
                              А вы в Баду пишете такой же простой и легкий код, как и на Обновлении остался? :)
                                0
                                Сформулируйте пожалуйста вопрос более четко.
                                  0
                                  Куда же четче?

                                  Очень глупо заявлять, что вот превращают php в java, при том, что, во-первых, ОО-модель пхп дерется с джавы, о чем открыто говорят сами разработчики, во-вторых, в любых развивающихся проектах использование ООП очень даже оправдывает себя, т.к. в итоге ваша система превращается в набор независимых модулей, которые позволяют малой кровью менять функционал проекта. При условии, что вы умеете писать вменяемый ОО код, а не делать 2-3 класса с 3-4-мя статическими методами по 300-400 строчек кода каждый.
                                  Так вот мне и интересно, Badoo очень большой проект. И у вас там все простенькими функциями написано, причем так, что возможно нормально поддерживать?
                                    0
                                    Я могу вам ответить с 80% вероятностью.

                                    Там все перемешано, и классы и функции, нет автолоада, запросы пишутся прямо в бизнес-логике. В представлении (если оно есть) предостаточно того, чего там быть не должно. Все кешируется, что можно.
                                    Программисты сидят не глупые. Достаточно большая команда, новички сидят в саппорте, исправляют все, что каждый день отваливается понемногу. Новичкам вникнуть в код и разобратся в проекте нужно от 2 до 6 месяцев.
                                      +1
                                      Вы работали в баду? О_о
                                        0
                                        Да нет, есть MVC, функции не используются, автолоад есть и т.д. :). Кешируется действительно всё, чтобы снять нагрузку на базы.
                                +2
                                Для меня одного слова Depency Injection, Inversion of Control и Namespace применительно к PHP, звучат вроде «Глянь какой у меня *censored* длинный» ??
                                  0
                                  А Namespace чем вас обидел? ;)
                                    0
                                    Изначально я хотел написать про DI и IoC, но в каждом файле не хочется писать такое:
                                    <?php
                                    use foo/bar;
                                    use your/exception as exception;
                                    use pdo, pdoexception;
                                    

                                    Поэтому добавил Namespace.

                                    И вообще, сейчас OOП применяется не по назначению довольно часто.
                                      0
                                      ...в каждом файле не хочется писать такое:...
                                      Дак никто вас не заставляет. Если в файле создается один экземпляр из foo/bar, пишите так:
                                      $f = new \foo\bar\class();
                                      
                                  –6
                                  > Как реанимировать ваш PHP-проект

                                  Здесь можно было останавливаться и писать: выкиньие РНР, пишите на чем-то другом :)
                                    0
                                    Здесь можно было остановиться, но я не смог:
                                    [imho]Нет ничего лучше, чтобы писать некрупные динамические сайты, чем PHP.[/imho]

                                    Понятно, что у того ЯП есть те плюсы, но проста написания кода/развертки приложения PHP просто умиляет.

                                    И да, я пишу на PHP, учу Python (давно уже пора) и люблю RoR (не знаю почему).
                                      0
                                      Простота написания кода — RoR
                                      А развертка — да, согласен
                                        0
                                        Под «написанием кода» я подразумевал порог вхождения для написания чего-то вроде сайта-визитки.
                                          0
                                          опять же RoR или какой-нит sinatra :)
                                            +1
                                            У меня развертка RoR на Webbynode и Heroku делается одной командой.
                                            Даже не знаю что может быть проще )
                                              0
                                              CI, например. Вообще ничего жать не надо :)
                                                0
                                                Ну как маркетинговый слоган вполне катит, но мы то знаем, что за этим «ничего жать не надо» стоит :)
                                                  0
                                                  На баше не оценят, но последние 3 коммента в контексте одного диалога меня очень даже улыбнули (:
                                              0
                                              ЯП != фреймворк
                                                0
                                                Я этого и не утверждаю :)

                                                Просто для того же Ruby простота написания выше, чем у PHP, особенно во фреймворках. За счет фич самого языка.
                                                  0
                                                  А я и не говорю «Выкиньте рельсы/синатру». Мне наоборот нравится, что там можно просто и без разговоров написать (поправьте, если что-то не так в коде, в руби не силен)

                                                  require 'sinatra'
                                                  
                                                  get '/' do
                                                      'Hello, Habr!'
                                                  end
                                                  


                                                  Но это уже не чистый руби =)
                                                    0
                                                    Ну, на чистых языках мало кто пишет :) Для того же «сайта-визитки» PHP быстр и удобен только пока там одна страница :) Как только страниц две, уже начинается «include header.php», «include footer.php» и т.п., что быстро становится кашей
                                                      0
                                                      При использовании фрэймворка, на пхп аналогично ), хоть и чуть больше строк
                                                      require 'Slim/Slim.php';
                                                      $app = new Slim();
                                                      $app->get('/', function () {
                                                          echo "Hello, Habr!";
                                                      });
                                                      $app->run();
                                                      


                                                      Python way)
                                                        0
                                                        Я коллаборатор фреймворка Slim, если что.
                                        +6
                                        $mailer = $this->container->get('mailer');
                                        

                                        И ни одна IDE не угадает, инстансом какого же класса будет являться $mailer. Очень удобно, да.
                                          +2
                                          PHPDoc решает это проблему.
                                            0
                                            Подскажите как
                                              +3
                                              /** @var $mailer Mailer */
                                              $mailer = $this->container->get('mailer');
                                              
                                                +2
                                                Это то понятно. Но автоматически это узнать нельзя. Да и беда сам разработчик не всегда может узнать что это за класс сюда попадает. Нужно дополнительно смотреть в конфигурацию контейнера.
                                                  0
                                                  PHPStorm 5 уже, вроде бы, умеет угадывать классы Symfony 2.
                                                    0
                                                    Классы симфони — да, немножко, а вот такого не умеет он этого, но они обещают в шестом — youtrack.jetbrains.com/issue/WI-6027
                                              –1
                                              Это не решение, это костыль для костыля.
                                                +4
                                                Предложите более удобный вариант. К примеру должен быть сервис, который умеет отправлять смс. При тестах или разработке отправлять реальные смски нельзя. Куда Вы будете его помещать?

                                                А вообще здесь лучше обсуждать подход, а не конкретное решение. Можно сделать и так:

                                                class MyCustomContainer extends Container
                                                {
                                                /**
                                                * return iMailer
                                                */
                                                public function getMailer()
                                                {
                                                return $this->get( 'mailer' );
                                                }

                                                /**
                                                * return iAnotherService
                                                */
                                                public function getAnotherService()
                                                {
                                                return $this->get( 'anotherService' );
                                                }
                                                }
                                                  +5
                                                  image
                                                    0
                                                    Иии? А ты наверное любитель магических геттеров/сеттеров?
                                                  0
                                                  // файл сервиса
                                                  class TestService
                                                  {
                                                      /**
                                                       * @var MailerInterface
                                                       */
                                                      protected $mailer;
                                                  
                                                      public function __construct(MailerInterface $mailer)
                                                      {
                                                          $this->mailer = $mailer;
                                                      }
                                                  }

                                                  # файл services.yml с описанием зависимостей сервисов
                                                  services:
                                                      test_service:
                                                          class: \TestService
                                                          arguments: [@mailer] 
                                                  

                                                  Сервис не должен ничего знать ни о контейнере, ни о геттерах для получения сервисов. У него должен быть интерфейс для внедрения зависимости, а в настройках контейнера вы уже описываете, что передать сервису. Есть еще несколько способов внедрения зависимостей, которые реализованы в Symfony 2, почитать можно здесь и здесь. А в документации можно посмотреть, что еще позволяет сделать контейнер в Symfony 2. А $mailer = $this->container->get('mailer'); это действительно костыль и плохой тон.
                                                    0
                                                    Это все красиво и замечательно, но покажите пожалуйста пример использования testService.
                                                +1
                                                Да ну? Смотрим внимательно :)
                                              +1
                                              Переводить на новую версию PHP можно только весь проект.
                                                +1
                                                Странно, но я как-то не согласен с автором.
                                                Порой для переноса аля у нас тут куча кода от разных разработчиков, где вроде все работает, но что-то поменять, исправить баг очень сложно, приходиться не пересмотреть весь код, и его хотя бы немного подготовить. Проверка такого кода и его связанности (особенно если есть приложения для моб. телефонов, партнерские програмы и т.д) вызавает большие трудности и занимает много времени.

                                                Я остановился на том что проще каждый месяц отъедать от работающего сайта по модулю, и переписывать его на фреймворке, покрывая тестами. + Пихать в SESSION\COOKIE данные которые необходимые для модулей на старой системе.
                                                  +1
                                                  Не понятно зачем подключать ClassLoader при использовании Composer, который внутри себя несет автолоад по psr-0 и классмап.
                                                    0
                                                    Тоже переписываю сейчас код, где есть куски из 90-х. Забавно читать однострочники на ~1000 символов, где и и onclick="..." и style="..." внутри html. Брр-р, дрожь по коже.

                                                    Так вот у меня есть убежденность: никакой фреймворк не решит проблем роста проекта. Фреймворк только помогает быстро стартануть. И скорее всего у вас появится свой фреймворк с нужной конкретно вам моделью компонентности, и который решает конкретно ваши задачи.
                                                    А вот в симфони можно подсматривать, да.

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

                                                    Самое читаемое