Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • SensioLabs Professional services to help you with Symfony
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by
  1. Home
  2. Documentation
  3. Symfony: The Fast Track
  4. Russian
  5. Изучение внутренностей Symfony

Изучение внутренностей Symfony

Мы уже достаточно долгое время используем Symfony и разработали внушительное приложение, при этом большая часть выполняемого кода является самим Symfony. Несколько сотен строк нашего кода и тысячи фреймворка.

Мне нравится узнавать, как всё работает изнутри. Я всегда был очарован инструментами, помогающими мне докопаться до сути. Первый раз, когда я использовал пошаговый отладчик или когда открыл для себя ptrace — это волшебные воспоминания.

Хотите лучше понять, как работает Symfony? Тогда самое время разобраться, что происходит под капотом вашего приложения. Вместо объяснения довольно скучной обработки HTTP-запроса с теоретической точки зрения, мы будем использовать Blackfire, чтобы наглядно посмотреть как всё работает, а также познакомиться с продвинутыми темами.

Разбираемся во внутренностях Symfony и Blackfire

Вы уже знаете, что все HTTP-запросы обрабатываются в одной точке входа — в файле public/index.php. Но что происходит потом? Как вызываются контроллеры?

Давайте спрофилируем английскую главную страницу на продакшене с помощью браузерного расширения Blackfire:

1
$ symfony remote:open

Или непосредственно через командную строку:

1
$ blackfire curl `symfony cloud:env:url --pipe --primary`en/

Откройте вкладку "Timeline" в профилировщике и вы увидите что-то похожее на это:

/

Наведите курсор на цветные полосы, расположенные на временной шкале, чтобы получить больше информации о каждом вызове; вы узнаете много нового о том, как работает Symfony:

  • Основной точкой входа является файл public/index.php;
  • Метод Kernel::handle() обрабатывает запрос;
  • Он вызывает HttpKernel, который отправляет несколько событий;
  • Первым создаётся событие RequestEvent;
  • Вызывается метод ControllerResolver::getController() для определения, какой контроллер должен обрабатывать входящий URL-адрес;
  • Вызывается метод ControllerResolver::getArguments() для определения того, какие аргументы нужно передать контроллеру (для этого используется преобразователь параметров);
  • Вызывается метод ConferenceController::index() и большая часть нашего кода выполняется этим вызовом;
  • Метод ConferenceRepository::findAll() получает все конференции из базы данных (обратите внимание на соединение с базой данных с помощью PDO::__construct());
  • Метод Twig\Environment::render() отображает шаблон;
  • Довольно быстро выполнились ResponseEvent и FinishRequestEvent, но, видимо, из-за того, что нет обработчиков этих событий.

Временная шкала — отличный способ понять, как работает код; она крайне полезна в случае унаследованного проекта, разработанного кем-то другим.

Теперь профилируйте ту же страницу с локального компьютера в окружении разработки:

1
$ blackfire curl `symfony var:export SYMFONY_PROJECT_DEFAULT_ROUTE_URL`en/

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

/

Вы понимаете, что происходит сейчас? У нас включено HTTP-кеширование, поэтому мы профилируем кеширующий слой Symfony HTTP. А так как страница закеширована, вызов HttpCache\Store::restoreResponse() получает HTTP-ответ из кеша, следовательно контроллер никогда не будет вызван.

Отключите кеширующий слой в public/index.php, как мы делали это в предыдущем шаге, и попробуйте снова профилировать код. Вы сразу увидите, что результат будет совершенно другим:

/

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

  • Обработка события TerminateEvent, которая не была видна в продакшене, выполняется довольно много времени; При внимательном рассмотрении, вы увидите, что это событие отвечает за хранение данных профилировщика Symfony, собранных во время запроса;
  • Под вызовом ConferenceController::index() обратите внимание на метод SubRequestHandler::handle(), который отображает ESI (поэтому у нас два вызова Profiler::saveProfile(): один для основного запроса, второй — для ESI).

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

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

Проведите несколько интересных экспериментов: профилируйте страницу с ошибкой, страницу с путем/ (которая является редиректом) или ресурс API. Каждое профилирование расскажет вам немного больше о том, как работает Symfony, какой класс или метод вызывается, что работает долго, а что — быстро.

Использование отладчика Blackfire Debug Addon

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

В командной строке используйте флаг --debug:

1
2
$ blackfire --debug curl `symfony var:export SYMFONY_PROJECT_DEFAULT_ROUTE_URL`en/
$ blackfire --debug curl `symfony cloud:env:url --pipe --primary`en/

В продакшене вы увидите, например, загрузку файла .env.local.php:

/

Откуда он взялся? Platform.sh выполняет оптимизацию при развёртывании приложения Symfony, например, оптимизирует автозагрузчик Composer (--optimize-autoloader --apcu-autoloader --classmap-authoritative). Также, чтобы не парсить файл .env с переменными окружения при каждом запросе, сгенерируем файл .env.local.php:

1
$ symfony run composer dump-env prod

Blackfire — очень производительный инструмент, который помогает понять, как выполняется PHP-код. Улучшение производительности — это только один из способов использования профилировщика.

Пошаговая отладка с Xdebug

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

Альтернативой отслеживания выполняемого кода является пошаговый отладчик, например, Xdebug. Пошаговый отладчик помогает интерактивно анализировать процесс выполнения программы и структуры данных, проходя через PHP-код проекта. Это очень полезный способ поиска и исправления непредсказуемой работы приложения, заменяющий стандартную технику отладку через вывод переменных на экран при помощи "var_dump()/exit()".

Сначала установите PHP-модуль xdebug. После чего проверьте правильность установки, выполнив команду ниже:

1
$ symfony php -v

В выводе команды должны быть сведения об установленном Xdebug:

1
2
3
4
5
6
PHP 8.0.1 (cli) (built: Jan 13 2021 08:22:35) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.1, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.1, Copyright (c), by Zend Technologies
    with Xdebug v3.0.2, Copyright (c) 2002-2021, by Derick Rethans
    with blackfire v1.49.0~linux-x64-non_zts80, https://blackfire.io, by Blackfire

Кроме этого, вы также можете проверить, что Xdebug настроен для работы с PHP-FPM, если откроете приложение, наведёте курсор мыши на логотип Symfony в панели отладки и перейдёте по ссылке "View phpinfo()":

/

Теперь включите режим отладки (debug) в Xdebug:

php.ini
1
2
3
[xdebug]
xdebug.mode=debug
xdebug.start_with_request=yes

По умолчанию Xdebug отправляет данные на порт 9003 локального сервера.

Xdebug можно запустить различными способами, но наиболее простой из них — воспользоваться средствами вашей IDE. В этой главе настройка Xdebug будет рассматриваться на примере использования редактора Visual Studio Code. Нам потребуется установить расширение PHP Debug, для этого запустите "Quick Open" (Ctrl+P), вставьте следующую команду и нажмите Enter:

1
ext install felixfbecker.php-debug

Создайте следующий файл конфигурации:

.vscode/launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for XDebug",
            "type": "php",
            "request": "launch",
            "port": 9003
        },
        {
            "name": "Launch currently open script",
            "type": "php",
            "request": "launch",
            "program": "${file}",
            "cwd": "${fileDirname}",
            "port": 9003
        }
    ]
}

С открытой директорией проекта в Visual Studio Code перейдите в отладчик и нажмите зелёную кнопку запуска с надписью "Listen for Xdebug":

Если вы сейчас обновите страницу с приложением в браузере, то автоматически откроется IDE, это означает, что сеанс отладки запущен. По умолчанию всё является точкой останова, поэтому выполнение кода остановится на первой инструкции. Теперь можно посмотреть значение переменных, пройтись по всем этапам выполнения кода, перейти в конкретную функцию и т.д.

При отладке вы можете снять галочку напротив точки останова "Everything" и добавить только нужные точки останова в коде.

Если вы плохо знакомы с пошаговыми отладчиками, ознакомьтесь с отличным руководством для Visual Studio Code, в котором всё наглядно объясняется.

Двигаемся дальше

  • Документация пошаговой отладки Xdebug;
  • Отладка с помощью Visual Studio Code.
Previous page Оптимизация производительности
Next page Использование Redis для хранения сессий
This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.
TOC
    Version

    Symfony 6.4 is backed by

    Take the exam at home

    Take the exam at home

    Save your teams and projects before they sink

    Save your teams and projects before they sink

    Version:
    Locale:
    ebook

    This book is backed by:

    see all backers

    Symfony footer

    Avatar of Peter Gribanov, a Symfony contributor

    Thanks Peter Gribanov for being a Symfony contributor

    1 commit • 2 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • What is Symfony?
      • Symfony at a Glance
      • Symfony Components
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • Symfony Community
      • SymfonyConnect
      • Events & Meetups
      • Projects using Symfony
      • Contributors
      • Symfony Jobs
      • Backers
      • Code of Conduct
      • Downloads Stats
      • Support
    • Blog

      • All Blog Posts
      • A Week of Symfony
      • Case Studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Living on the edge
      • Releases
      • Security Advisories
      • Symfony Insight
      • Twig
      • SensioLabs Blog
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Powered by

    Follow Symfony