Debugging a PHP applications on a production server using Xdebug and the CLI
Topics covered:
The ability to effectively debug is becoming essential for every PHP programmer. Xdebug, a powerful debugging tool for PHP, offers solutions that surpass traditional methods such as log analysis, print_r, var_dump, or echo, especially in production environments. In 2024, knowledge of Xdebug and the ability to utilize it highlight the difference between a good and a great PHP programmer.
What is Xdebug?
Xdebug is a tool for PHP that enables not only tracing code execution to generate test coverage reports but also debugging code by stopping at specific points, known as breakpoints. This allows developers to precisely analyze variable values and the context of script execution, which is crucial for identifying and resolving issues in the code.
Why Does Xdebug Surpass Traditional Methods?
Although methods like print_r, var_dump, or echo can be useful in solving everyday programming problems, they often prove insufficient for more complex errors, especially those occurring asynchronously or requiring deeper context. Xdebug offers significantly more advanced capabilities, such as conditional code stopping and detailed variable analysis, making it an invaluable tool in the hands of an experienced programmer.
Debugging in Production with Xdebug
Debugging applications in a production environment, where disrupting service to users is not an option, can be challenging. Typically, such situations require cloning the production environment and testing the specific state of the application under isolated conditions, a process that is usually very complicated and time-consuming. A much faster solution is remote debugging using Xdebug through a CLI tool like dbgpClient, which allows connection to the production server without direct interference with its operations.
How to Use dbgpClient?
DbgpClient is the official Xdebug client for command lines, which facilitates seamless connection to the Xdebug server. It requires the Xdebug plugin to be installed and properly configured, but this allows for effective debugging of applications, including setting breakpoints, analyzing code execution context, and controlling the further course of code.
Analysis and Debugging in a Docker Environment
The modern approach to deploying applications increasingly relies on containerization, with Docker becoming the industry standard. Consequently, debugging applications in a Docker-based environment takes on a new dimension, enabling the simulation of the production environment on a test server. Let's move to practical analysis with an example of simple PHP code to see how Xdebug can support the problem-solving process in such a configured environment.
Sample Code for Analysis
Assuming our test server operates in a containerized Docker environment, this allows easy replication of the production server's configuration, which is key for credible debugging. The following simple piece of PHP code will be the subject of our analysis:
Installing dbgpClient in a Docker Environment
To begin debugging with Xdebug, a key step is downloading and installing the dbgpClient, which enables interaction with Xdebug. Executable files for various operating systems are available on the official Xdebug website: https://xdebug.org/download#dbgpClient.
In the context of testing in a Docker-based environment, the version for Linux x86_64 is particularly recommended. To download the file, we will use the wget tool, which is a standard practice in Unix systems. This process is simple and quick, allowing for efficient preparation of the debugging environment.
wget https://xdebug.org/files/binaries/dbgpClient
I grant permissions and move it to the bin directory so that it is accessible from anywhere in the system:
chmod +x dbgpClient
mv ./dbgpClient /usr/local/bin/dbgpClient
I check if the program is working correctly:
As you can see, the program has started listening on port 9003. Refresh the page where the application is running; the expected response should be the following view:
If the code does not stop and the message "Waiting for debug server..." appears on the screen, the likely cause is either the Apache server has not been reloaded or there is a problem with the Xdebug configuration.
Configuration
Below, I provide my configuration in the Docker container:
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
Realise your web development project with us.
Debugging with dbgpClient and XDebug
Once XDebug is properly configured, we can proceed to the actual debugging process. A key element here is the use of breakpoints, which allow the execution of the code to be halted at a selected point, invaluable for analysis and problem-solving.
Adding Breakpoints
Breakpoints allow the execution process of the program to be stopped at a selected point. To set a breakpoint in dbgpClient, we use the command:
breakpoint_set -t line -f file:///var/www/html/index.php -n 5
where the option -f specifies the file, and -n the line on which we want to stop execution. In this example, the breakpoint will be set in the file index.php on line 5.
Conditional Breakpoints
We can also set conditional breakpoints, which will stop the code only when a specific condition is met, such as when the value of a variable exceeds a certain number. We use the command for this:
breakpoint_set -t line -f file:///var/www/html/index.php -n --base64(expression)
Other Ways to Set Breakpoints
More detailed and specific use cases for the breakpoint command or commands are available in the documentation at this link: https://xdebug.org/docs/dbgp#breakpoints
Continuing the Program
After setting a breakpoint, to continue script execution, we use the command:
run
If the script stops at the set breakpoint, we can check the state of variables at that moment.
Checking the Context
To see the values of variables at the stop point, we use the command context_get
The script stopped at line 5, which is responsible for assigning a value to the variable `$pow`. We notice that the value of this variable is marked as "uninitialized", which means it has not yet been initiated. Meanwhile, the value of the variable `$sum`, assigned at line 3, is 6. We can also determine the type of the variable, which is particularly useful in PHP - a language that allows for dynamic changes in variable types and their mixing during program execution.
Other Uses
Additional usage methods are available at the link here: https://xdebug.org/docs/dbgp#context-get
Stepping Into the Next Line
A significant aspect of the debugging process is the ability to step through the code - line by line - or enter into a function called in the program. To achieve this, we use the following command:
This command either moves the execution to the next line of code or stops at the beginning of the first line of the function called in the program. In the analyzed case, the stop occurred on line seven, as the sixth line contains no code.
At this point, we are able to reassess the program's operating context. It is expected that a value will be assigned to the variable $pow, which should reach the value of 46656.
Other Methods of Continuing the Program
DbgpClient also has other continuation methods, which are available in the documentation at this link: https://xdebug.org/docs/dbgp#continuation-commands
Retrieving the Value of a Specific Variable
There may be situations where objects or arrays are stored in a particular variable. In such a case, the function context_get will only provide us with basic information about the type of object, not revealing its value. To obtain complete information about the contents of a variable, the following command should be used:
property_get -n $pow
In this situation, a value was obtained using context_get, as the analyzed variable is of a primitive type. Nevertheless, this command will be extremely useful for analyzing object fields.
Other Ways to Retrieve Variable Values
The client also has other methods for retrieving variables, detailed descriptions of which are available at this link: https://xdebug.org/docs/dbgp#property-get-property-set-property-value
Summary
The aim of this article was to present an alternative way of debugging production code, diverging from traditional methods such as "print_r", "var_dump", etc., known to every programmer. DbgpClient also proves useful in debugging a local work environment, especially when using an editor without an officially integrated client, such as Vim or Zed.
Considering this tool becomes particularly important when our program operates in a Docker-based environment. Under such conditions, configuration can be exceptionally complicated, but dbgpClient is easy to install on any machine, even one operating in a Docker container.
The debugging method presented in the article, although it may seem complicated at first, is much faster than configuring XDebug in PHPStorm for code run in Docker. The commands described in this article constitute a basic set of tools available in the documentation at: https://xdebug.org/docs/dbgpClient.