Привет. Я тут на досуге написал скрипт, которым подменил php-интерпретатор в NetBeans.
Об установке и настройке этой IDE я подробно рассказывал в этой статье: Настройка среды php-разработки с нуля на NetBeans + php + docker + xdebug3. Она тоже будет тебе полезна, часть информации по отладке ты можешь черпануть оттуда. Здесь я буду запускать скрипты штатными средствами.
Как известно, NetBeans сам не умеет запускать консольные скрипты, которые находятся внутри контейнера. Здесь же я покажу как я решил эту проблему и теперь запускаю скрипты не из терминала, а одной кнопкой в гуйне. В целом, как показывает практика, решение работает исправно.
В прошлом посте я придумал простейший скрипт, который в этом немного помог. Вот его исходный вид:
#!/bin/bash
docker exec test-php php \
-dxdebug.mode=debug \
-dxdebug.start_with_request=1 \
`basename ${BASH_ARGV[0]}` \
"${@:1:$#-1}"
Но он был неуниверсальным и грубым. Он не учитывал много чего, что можно настроить в разделе ‘Run Configuration’ окна ‘Project Properties’:
В итоге у меня получился скрипт-хелпер (враппер, оболочка, прокси, как угодно), который вызывается из IDE будто это настоящий интерпретатор, но внутри она подменяется хитро построенной командой docker exec
.
Я сознательно писал всё на баше, чем достиг простоты в реализации, изучении и переиспользовании. Можно было бы написать плагин, но мне лень разбираться в структуре и экосистеме IDE.
Он же есть в репозитории nb-test из прошлой статьи. Вставлять его целиком сюда не буду — он получился слишком большим (в основном, из-за справки и подробных комментариев).
Оглавление
Как настроить хелпер?
Предполагается, что у тебя прямо сейчас уже бежит рабочий контейнер с пыхой и xdebug. Если не — обращайся сюда.
Файл хелпера называется php
не просто так: NB не позволяет указывать иной путь до интерпретатора в своих настройках. Поскольку мой нужен для подмены настоящего контейнерным, то и имя у него соответствующее. Учитывай это и не путайся.
Ниже я очень подробно расписал эти шаги, но пугаться не стоит — всё очень легко. Просто текста получилось много.
Вариант 1: локальный
- Сохрани файл в директорию
nbproject
твоего проекта. Например, путь может быть таким:/home/user/bla/nbproject/php
гдеphp
— это скачанный тобой файл. - Убедись, что он исполняем. Если не, тогда:
chmod +x /home/user/bla/nbproject/php
- Открой NetBeans. В выпадашке ‘Set project configuration’ тулбара ‘Run’ выбери ‘Customize…’.
- Параметр ‘Run as’ выстави в значение ‘Script (run in command line)’.
- Отпусти птичку ‘Use default PHP Interpreter’.
- В поле ‘PHP Interpreter’ вставь лапками путь из п.1. Кнопка ‘Browse’ не спасёт, ибо окно выбора файла скрывает директорию
nbproject
.
Если ты изменяешь конфигурацию <default>
, то дальнейшие шаги 7-10 необязательно повторять для всех остальных. Тогда конфигурации отличаются только настройками, которые описаны в пп. 4-6.
- В поле ‘PHP Options’ впиши следующее:
--container=<name>
где<name>
— имя бегущего контейнера с пыхой и xdebug. Если в этом поле у тебя другие аргументы, просто добавь к ним этот.
Да, знак =
обязателен. Именем контейнера станет всё от знака =
до ближайшего пробела или конца строки аргументов. Корректное имя можно увидеть в docker ps
или docker-compose.yml
твоего проекта.
Нет, это не аргумент php
. Это аргумент, который обрабатывается хелпером для формирования команды docker exec
. Он обязателен, но больше он ни для чего не нужен.
- Чтобы форсировать подключение xdebug из контейнера к NB, добавь на шаге 7 ещё такие аргументы:
-dxdebug.mode=debug
-dxdebug.start_with_request=1
Описание параметров xdebug доступно здесь. - Если в твоём проекте есть вложенная директория с php-исходниками проекта и в контейнер проброшена именно она, а не весь проект целиком, тогда добавь на шаге 7 ещё такой аргумент:
--map=<local_path>:<docker_path>
где:<local_path>
— абсолютный путь до локальной директории с php-исходниками (нужным php-скриптом) на хосте;<docker_path>
— абсолютный путь до тех же исходников внутри контейнера.
Да, знак =
обязателен. Значением станет всё от знака =
до ближайшего пробела или конца строки аргументов.
Да, знак :
обязателен. Это разделитель двух путей. Если ничего не будет слева или справа от :
, либо не будет самого :
, то хелпер выплюнет ошибку.
Нет, это не аргумент php
. Это аргумент, который обрабатывается хелпером для формирования команды docker exec
. Он НЕобязателен и больше он ни для чего не нужен.
- При вызове мой хелпер выводит некоторую информацию перед запуском пыхи. Чтобы отключить этот вывод и сразу запустить php-скрипт, добавь на шаге 7 такой аргумент:
--quiet
Нет, никакие ошибки или другой вывод таким образом не будут заглушены.
Нет, это не аргумент php
. Это аргумент, который обрабатывается хелпером перед запуском php. Он НЕобязателен и влияет только на собственный вывод хелпера.
- По необходимости укажи другие параметры и сохрани конфигурацию.
Вариант 2: глобальный
- Сохрани файл в любую понравившуюся тебе директорию. Например, путь может быть таким:
/home/user/php
гдеphp
— это скачанный тобой файл. - Убедись, что он исполняем. Если не, тогда:
chmod +x /home/user/php
- Открой ‘Tools’ > ‘Settings’ > ‘PHP’ > ‘General’.
- В параметре ‘PHP Interpreter’ укажи полный путь из шага 1.
- Повтори шаги 3-4 и 7-11 из варианта 1.
Как ловить точки останова?
- Убедись, что при настройке конфигурации запуска ты выполнил шаг 8 из варианта 1.
- Выбери настроенную конфигурацию запуска.
- Поставь бряк в любом месте того php-кода, который отработает при запуске настроенного скрипта.
Я всё настроил!
На тулбаре ‘Run’ есть пимпа ‘Debug Project’ — трогни её. NB сразу запустит скрипт, который инициирует подключение xdebug из контейнера со скриптом, и начнёт слушать порт xdebug, ожидая это входящее подключение.
Как работает хелпер?
Вот снова скриншот окна для управления конфигурациями запуска проекта:
Цифрами на скриншоте выделены:
- Тип запуска php-скрипта (установлен запуск в качестве cli-команды).
- Выключенный чекбокс позволяет указать явно конкретный интерпретатор
php
для запуска в п. 3. - Путь до интерпретатора при выключенном чекбоксе ‘Use Default PHP Interpreter’. Обязан быть корректным и оканчиваться на
php
. Именно поэтому хелпер называетсяphp
. То же ограничение в настройках самого NB. - Путь до запускаемого скрипта (php-файла) относительно корня проекта.
- Аргументы для этого скрипта.
- Рабочая директория. Вообще, при вызове
php
этот путь будет текущимpwd
в рамках процесса, но в нашем контексте это бессмысленно, безполезно, не учитывается и не рассматривается. - Аргументы php-интерпретатора (не php-скрипта!). Здесь можно (пере)определить настройки
php.ini
.
Вот команда, которая построена IDE и вызывается для конфигурации со скриншота (я порвал её по строкам для удобства):
"/home/anthony/projects/nb-test/nbproject/php" \
"--container=test-php" \
"--map=/home/anthony/projects/nb-test/app:/var/www" \
"-dxdebug.mode=debug" \
"-dxdebug.start_with_request=1" \
"/home/anthony/projects/nb-test/app/index.php" \
"arg1" \
"arg2"
Здесь, построчно:
- Путь до моего хелпера. Настраивается явно в конфигурации (как на скриншоте; «локально», в рамках конфигурации текущего проекта) или в настройках NB (глобально).
- Аргумент хелпера. Здесь указывается имя контейнера, в котором существует (или из коего доступен) скрипт для запуска.
- Аргумент хелпера. Содержит проброс путей php-исходников с хоста в контейнер. Так хелпер понимает, что в контейнере не весь проект, а только его вложенная директория с php-исходниками. Значит, вызывать скрипт надо по другому пути, а не относительно текущего
WORKDIR
контейнера. - Опция
xdebug
, включающая отладку кода (точки останова). - Опция
xdebug
, включающая автоматическое подключение к порту хоста при начале работыphp
. - Скорректированный абсолютный путь до файла php-скрипта, который будет запущен интерпретатором.
- Тестовый аргумент для php-скрипта.
- Тестовый аргумент для php-скрипта.
Обрати внимание на порядок кусков команды: интерпретатор => его аргументы => путь до скрипта => его аргументы.
Эту строку формирует и вызывает NB на локальном компе. А вот, что мне надо вызвать:
docker exec \
<имя_контейнера> \
php \
[<аргументы_php>] \
<php_скрипт> \
[<аргументы_скрипта>]
Чтобы перекромсать её, я пошёл простым путём. Взяв эту команду как массив подстрок, разделённых пробелами, я пошёл по ним циклом. Собирая попутно все кусочки команды, я проверяю является ли очередной кусок файлом существующим на диске. Если да, то преобразовываю его путь (о чём ниже) и собираю оставшиеся флаги в конец. По пути также цепляю имя контейнера и мап путей, который прямо влияет на преообразование пути к скрипту.
Таааааак, дальше пошли нюансики!
Нюансик 0. У нас в IDE уже есть готовое окно, в котором можно установить всё необходимое для старта отладки cli-скрипта в докере. Оно на скриншотах выше. Мы будем использовать это окно вполне штатно.
Нюансик 1. Нам нельзя просто взять и запустить любой скрипт в каком-то контейнере. То есть, вообще, технически, можно, однако контейнер для начала надо (создать и) запустить.
Здесь же предполагается, что над php-проектом уже идёт работа в докере. Поэтому контейнер обязан существовать и быть запущенным. Для указания его имени я ввёл аргумент --container
, который вводится в ‘PHP Options’.
Нюансик 2. Сам php-скрипт должен быть доступен внутри контейнера: либо находясь внутри вольюма (volume), либо прокидываясь вольюмом с диска хоста. Поэтому нам требуется преобразовать путь к php-скрипту: тот абсолютный (хостовый), что выдал NB, внутри контейнера будет некорректным. Нам нужен относительный.
По умолчанию предполагается, что этот путь относителен текущего WORKDIR
контейнера. Тогда я вырезаю из абсолютного кусок от корня до текущей директории проекта. Она определяется как абсолютный путь до хелпера минус два куска справа. Таким образом,
/home/anthony/nb-test/nbproject/php
преобразовывается в
/home/anthony/nb-test
и это вырезается из абсолютного пути к файлу php-скрипта.
Другой сценарий, когда в ‘PHP Options’ ты указываешь `—map`. Тогда из абсолютного пути к скрипту вырезается левая часть мапа и конкатенируется с правой. В итоге получается абсолютный путь к файлу уже внутри контейнера.
Нюансик 3. Интерпретатор в NB можно настроить как в рамках одной конфигурации запуска проекта, так и в глобальных настройках. Отсюда закономерно родились два способа использования хелпера: глобальный и локальный. При глобальном хелпер лежит где угодно на хосте, при локальном — в директории nbproject
проекта. Эта директория — единственный признак, по которому хелпер может найти папку с исходниками.
Нюансик 4. Я тут уже упомянул рабочую директорию. По умолчанию, это директория проекта, но в окне настройки конфигурации запуска её можно явно переопределить. Тогда, перед стартом скрипта, указанный путь станет pwd для пыхи.
Как показали мои изыскания, это стоит заигнорить и никогда не трогать. А жаль.
В итоге, собрав в горсть все собранные параметры и расставив их все по местам, получаем команду:
docker exec \
test-php \
php \
-dxdebug.mode=debug \
-dxdebug.start_with_request=1 \
/var/www/index.php \
arg1 \
arg2
Изучив код, можно изрядно повонять. А по-моему, получилось неплохо. Вот результат:
Обращаюсь к виндузятам. Полагаю, вам будет проще переписать этот хелпер самостоятельно на cmd, powershell или компилируемом языке. Сорян, но я не хочу погружаться в эту кроличью нору, ибо в первую очередь решал сугубо свою проблему.
Если этот скрипт будет полезен кому-то — огонь. Алоха.