Debugowanie aplikacji PHP na serwerze produkcyjnym, z użyciem Xdebug i CLI
Poruszone tematy:
Umiejętność efektywnego debugowania staje się niezbędna dla każdego programisty PHP. Xdebug, potężne narzędzie debugowania dla PHP, oferuje rozwiązania, przewyższające tradycyjne metody, takie jak analiza logów, print_r, var_dump, czy echo, zwłaszcza w kontekście środowisk produkcyjnych. W 2024 roku, znajomość Xdebug i umiejętność jego wykorzystania podkreśla różnicę między dobrym a świetnym programistą PHP.
Co to jest Xdebug?
Xdebug, to narzędzie dla PHP, umożliwiające nie tylko mapowanie przebiegu kodu do generowania raportów pokrycia testami, ale również debugowanie kodu przez zatrzymywanie w określonych punktach, tzw. breakpointach. Dzięki temu, programiści mogą precyzyjnie analizować wartości zmiennych i kontekst wykonywania skryptu, co jest kluczowe dla identyfikacji i rozwiązywania problemów w kodzie.
Dlaczego Xdebug przewyższa tradycyjne metody?
Chociaż metody, takie jak print_r, var_dump czy echo mogą być przydatne w rozwiązywaniu codziennych problemów programistycznych, często okazują się niewystarczające w przypadku bardziej złożonych błędów, szczególnie tych występujących asynchronicznie lub wymagających głębszego kontekstu. Xdebug oferuje zdecydowanie bardziej zaawansowane możliwości, takie jak warunkowe zatrzymywanie kodu i szczegółowa analiza zmiennych, co czyni go nieocenionym narzędziem w rękach doświadczonego programisty.
Debugowanie na produkcji z Xdebug
Wyzwaniem może być debugowanie aplikacji w środowisku produkcyjnym, gdzie nie można sobie pozwolić na przerwanie działania aplikacji dla użytkowników. Zazwyczaj w takich przypadkach konieczne jest sklonowanie środowiska produkcyjnego i przetestowanie danego stanu działania aplikacji w izolowanych warunkach, co zazwyczaj jest bardzo skomplikowanym i czasochłonnym procesem. Innym, znacznie szybszym rozwiązaniem jest zdalne debugowanie przy użyciu Xdebug poprzez narzędzie CLI, takie jak dbgpClient, co umożliwia podłączenie się do serwera produkcyjnego bez konieczności bezpośredniego ingerowania w jego działanie.
Jak korzystać z dbgpClient?
DbgpClient to oficjalny klient Xdebug dla linii poleceń, który pozwala na bezproblemowe łączenie się z serwerem Xdebug. Wymaga zainstalowanego pluginu Xdebug oraz odpowiedniej konfiguracji, ale dzięki temu umożliwia skuteczne debugowanie aplikacji, w tym ustawianie breakpointów, analizę kontekstu wykonania kodu oraz kontrolę nad jego dalszym przebiegiem.
Analiza i debugowanie w środowisku Dockerowym
Współczesne podejście do wdrażania aplikacji coraz częściej opiera się na konteneryzacji, a Docker stał się standardem w branży. W związku z tym, debugowanie aplikacji w środowisku opartym na Dockerze nabiera nowego wymiaru, umożliwiając symulację środowiska produkcyjnego na serwerze testowym. Przejdźmy do praktycznej analizy na przykładzie prostego kodu PHP, aby zobaczyć, jak Xdebug może wspierać proces rozwiązywania problemów w tak skonfigurowanym środowisku.
Przykładowy kod do analizy
Zakładamy, że nasz serwer testowy działa w konteneryzowanym środowisku Docker. To pozwala na łatwe replikowanie konfiguracji serwera produkcyjnego, co jest kluczowe dla wiarygodnego debugowania. Poniższy prosty fragment kodu PHP będzie przedmiotem naszej analizy:
Instalacja dbgpClient w środowisku Docker
Aby zacząć debugowanie z wykorzystaniem Xdebug, kluczowym krokiem jest pobranie i zainstalowanie klienta dbgpClient, który umożliwia interakcję z Xdebug. Pliki wykonywalne dla różnych systemów operacyjnych są dostępne na oficjalnej stronie Xdebug pod adresem: https://xdebug.org/download#dbgpClient.
W kontekście testowania w środowisku opartym na Dockerze, szczególnie zalecana jest wersja dla systemu Linux x86_64. Aby pobrać plik, wykorzystamy narzędzie wget, co jest standardową praktyką w systemach Unixowych. Proces ten jest prosty i szybki, co pozwala na efektywne przygotowanie środowiska do debugowania.
wget https://xdebug.org/files/binaries/dbgpClient
Nadaje uprawnienia i przenosze do katalogu bin, tak, żeby był dostępny z każdego miejsca w systemie:
chmod +x dbgpClient
mv ./dbgpClient /usr/local/bin/dbgpClient
Sprawdzam czy program działa prawidłowo:
Jak widać, program rozpoczął nasłuchiwanie na porcie 9003. Odśwież stronę na której jest aplikacja spodziewaną reakcją powinien być następujący widok:
Jeśli kod nie zatrzymuje się i na ekranie wyświetla się komunikat "Waiting for debug server...", prawdopodobnie przyczyną jest brak ponownego załadowania serwera Apache lub problem z konfiguracją Xdebug.
Konfiguracja
Poniżej zamieszczam swoją konfigurację w kontenerze dockerowym
zend_extension=xdebug
xdebug.start_with_request=yes
xdebug.client_port=9003
xdebug.client_host=127.0.0.1
xdebug.mode=develop,debug
xdebug.discover_client_host=1
Zrealizuj z nami swój projekt z zakresu web developmentu.
Debugowanie za pomocą dbgpClient i XDebug
Gdy XDebug jest skonfigurowany prawidłowo, możemy przejść do właściwego procesu debugowania. Kluczowym elementem jest tutaj użycie breakpointów, które umożliwiają zatrzymanie wykonania kodu w wybranym miejscu, co jest nieocenione przy analizie i rozwiązywaniu problemów.
Dodawanie breakpointów
Breakpointy pozwalają na zatrzymanie procesu wykonania programu w wybranym punkcie. Aby ustawić breakpoint w dbgpClient, używamy polecenia:
breakpoint_set -t line -f file:///var/www/html/index.php -n 5
gdzie opcja -f określa plik, a -n linię, na której chcemy zatrzymać wykonanie. W tym przykładzie breakpoint zostanie ustawiony w pliku index.php na linii 5.
Breakpointy warunkowe
Możemy również ustawić breakpointy warunkowe, które zatrzymają kod tylko wtedy, gdy spełniony jest określony warunek, np. gdy wartość zmiennej przekroczy pewną liczbę. Używamy do tego polecenia:
breakpoint_set -t line -f file:///var/www/html/index.php -n --base64(expression)
Inne sposoby ustawiania breakpointów
Bardziej szczegółowe i specyficzne przypadki użycia komendy lub komend breakpointowych dostępne są w dokumentacji pod tym linkiem: https://xdebug.org/docs/dbgp#breakpoints
Kontynuowanie programu
Po ustawieniu breakpointu, aby kontynuować wykonanie skryptu, stosujemy polecenie:
run
Jeżeli skrypt zatrzymał się na ustawionym breakpointcie, możemy sprawdzić stan zmiennych w danym momencie.
Sprawdzenie kontekstu
Aby zobaczyć wartości zmiennych w miejscu zatrzymania, używamy polecenia context_get
Skrypt zatrzymał się na linii 5, która odpowiada za przypisanie wartości do zmiennej `$pow`. Zauważamy, że wartość tej zmiennej jest oznaczona jako "uninitialized", co oznacza, że nie została jeszcze zainicjowana. Z kolei wartość zmiennej `$sum`, przypisana w linii 3, wynosi 6. Możemy także określić typ zmiennej, co jest szczególnie użyteczne w PHP - języku pozwalającym na dynamiczną zmianę typów zmiennych i ich mieszanie w trakcie wykonania programu.
Inne sposoby użycia
Dodatkowe sposoby użycia dostępne są pod linkiem tutaj: https://xdebug.org/docs/dbgp#context-get
Przejście linię dalej
Istotnym aspektem procesu debugowania jest możliwość krokowego przeglądania kodu - linia po linii - lub wchodzenia do funkcji wywoływanej w programie. Aby to osiągnąć, stosujemy następującą komendę:
Ta komenda albo przesuwa wykonanie do następnej linii kodu, albo zatrzymuje się na początku pierwszej linii funkcji wywołanej w programie. W analizowanym przypadku, zatrzymanie nastąpiło na linii siódmej, gdyż szósta linia nie zawiera kodu.
W tym punkcie jesteśmy w stanie ponownie ocenić kontekst działania programu. Oczekuje się, że nastąpi przypisanie wartości do zmiennej $pow, która powinna osiągnąć wartość 46656.
Inne metody kontynuacji programu
DbgpClient posiada również inne metody kontynuacji, które dostępne są w dokumentacji pod tym linkiem: https://xdebug.org/docs/dbgp#continuation-commands
Pobieranie wartości konkretnej zmiennej
Możliwe jest wystąpienie sytuacji, w której w określonej zmiennej przechowywane są obiekty lub tablice. W takim wypadku, funkcja context_get dostarczy nam jedynie podstawowych informacji dotyczących typu obiektu, nie ujawniając jego wartości. Aby uzyskać kompletną informację o zawartości zmiennej, należy zastosować poniższą komendę:
property_get -n $pow
W tej sytuacji otrzymano wartość z użyciem context_get, co wynika z faktu, iż analizowana zmienna jest typu prymitywnego. Niemniej jednak, ta komenda okaże się niezwykle przydatna podczas analizowania pól obiektów.
Inne sposoby pobierania wartości zmiennych
Klient posiada również inne metody pobierania zmiennych dokładne ich opisy dostępne są pod tym linkiem: https://xdebug.org/docs/dbgp#property-get-property-set-property-value
Podsumowanie
Celem tego artykułu było przedstawienie alternatywnego sposobu debugowania kodu produkcyjnego, odbiegającego od tradycyjnych metod, takich jak "print_r", "var_dump" itd., znanych każdemu programiście. DbgpClient okazuje się przydatny również przy debugowaniu lokalnego środowiska pracy, zwłaszcza gdy używamy edytora bez oficjalnie wbudowanego klienta, np. Vim czy Zed.
Rozważenie tego narzędzia staje się szczególnie istotne, gdy nasz program funkcjonuje w środowisku opartym na Dockerze. W takich warunkach, konfiguracja może być wyjątkowo skomplikowana, lecz dbgpClient jest łatwy do zainstalowania na każdej maszynie, nawet działającej w kontenerze Docker.
Metoda debugowania prezentowana w artykule, mimo że może wydawać się na początku skomplikowana, jest znacznie szybsza niż konfigurowanie XDebug w PHPStorm dla kodu uruchomionego w Dockerze. Komendy, które zostały opisane w tym artykule, stanowią podstawowy zestaw narzędzi dostępnych w dokumentacji pod adresem: https://xdebug.org/docs/dbgpClient.