Creating a good software involves several skills – analytical thinking, algorithms, design, coding etc and last but important – debugging. Debugging is an art of tracing and fixing the bugs, mastery of which saves a lot of time of the developer.
Looking from a debugging exposure perspective there has been a (probably unexplained) bias between developers of different programming languages. C has a powerful gdb, ddd, CDT; Java has Eclipse, IntelliJ IDEA. Developers are familiar and frequently use these debugging tools. Coming to a favourite web programming language – PHP. It has some decent debugging tools – Zend, Xdebug etc. However, these aren’t into wide usage. This blog post is my attempt to help PHP developers overcome this. This is the first such post in the series and hence has been simplified so that almost all PHP coders can follow it.
Lets start it with the Basic Debugging techniques
Basic Debugging
print_r(), var_dump(), debug_print_backtrace() and die()
Today, most developers still rely on these functions for debugging. I too relied on these function for a long time. For a small codebase, there is no problem with these functions. But for large applications, typically involving frameworks, it quickly becomes unwieldy. Consider these challenges
- For QA and production deployment we need to remove functions from the codebase. But what happens if we forget to remove these from code? It may
- expose the sensitive details if you forget to remove print_r on your Session Data. This would be an open invitation to hackers !
- let a user know your code structure when you left the debug_print_backtrace() in the code.
- expose the business critical or privacy-sensitive data even to the naive users
- These nasty print statements may break ajax requests because of unintended data in response
- Cause a performance impact. Remember, these statements cannot be disabled by just configuration – they must be removed completely
So, what do we do now? Fortunately, we have tools like
- Logging
- PHP Error Handling Function and Configuration
- Interactive Debugging Tool (XDebug)
- Profiling Tools (XHProf)
I shall be covering the first three one by one.
Logging
Logging is one of the best techniques to make debugging efficient. A healthy logging practice make an application easier to Debug. As a practice in my team, whenever a bug-report is filed, we view the log as a starting point for debugging. Most of the times we are able to fix bugs just by viewing the logs.
In production, enable these log levels
- Warning
- Fatal
In development environment, it is suggested to enable these levels
- Notice (Information Message)
- Warnings (Actionable Message)
- Fatal Errors
Also, contrary to a popular saying – “Warnings are meant to be ignored” – never ever ignore a warning. It is very important that Warning is handled during the development phase itself
Also give a serious thought on the strategy to put log statements. What should be logged and what shouldn’t be calls for a dedicated blog article for itself. I’ll skip the details and suggest you to read the Logging Best Practices article.
Error Handling functions
Setting up the development environment correctly improves our debugging and development capability. PHP has configuration parameters which will ease the debugging purpose. I prefer the below configuration for the development environment.
Development Environment Configuration
Name | Prefered Configuration | Description |
log_errors | true | Setting it to true will enable the error logging |
log_errors_max_len | 1024 | Set the maximum length of each log record |
error_log | /var/log/php/php_error.log | Set the file on which the error will be logged. We prefer to log errors of each technology in a separate folder, it make it easier to manage the logs. |
error_reporting | E_ALL | Setting to E_ALL will enable logging of all type errors. Notice cover best practices and coding standards. example – using an uninitialized variable. Warning is the Actionable error which suggest you to take an action and will not halt the program Example – Argument is missing in the function. Fatal Error on which the program will halt which need to be resolved at that instance. Example – Class not found Error. |
display_errors | true | Enabling it will write the message on the webpage. Which will give the visibility of errors |
html_errors | true | Enabling it will do the formatting of errors in the webpage which make it easier to read the errors. |
ignore_repeated_errors | false | I prefer to set it on TRUE in Production Environment as it will not log the repeated errors. This makes a usually lengthy and cumbersome log file to be precise and short . |
ignore_repeated_source | false | Setting to TRUE will prevent the log of repeated errors even from the different source. |
track_errors | true | If enabled, last error message will always be present in the global variable $php_errormsg. You have written a code to open a file and it fails due to some reason then that error message will be set in this variable. |
Read article PHP Error Handling via .htaccess and Error Handling and Logging for detailed understanding of these configurations.
Advanced Debugging
In Advanced Debugging, we will discuss about Eclipse and XDebug
XDebug empowers the php interpreter to connect with interactive debugging tools such as Eclipse.
Eclipse is a popular IDE (Integrated development Environment) which takes care about syntax Highlighting, Code Formatting and Code Completion etc. It will notify most of the issues related to syntax during coding itself. For debugging, it has breakpoints, watch expressions, variable view etc
XDebug can be used for tracing, debugging and profiling.
Installation of XDebug
XDebug is the pecl extension and can be installed with pecl command
Linux
pecl install xdebug
Windows
In Windows, if you are using Xampp, you just need to enable XDebug it in php.ini
Configuration of XDebug for Remote Debugging
Linux (the path may vary for some Linux distros)
vim /etc/php.ini
Windows
Locate php.ini and edit it php.ini using notepad or any other text-editor
[xdebug]
zend_extension=/usr/lib64/php/modules/xdebug.so
xdebug.remote_enable = On
xdebug.remote_autostart = On
xdebug.remote_port = 9000
xdebug.remote_host = localhost
zend_extension specifies the path of the XDebug Module
xdebug.remote_enable specifies whether the extension is active or not
xdebug.remote_host is the IP address of the machine where Eclipse will be running. This is typically the same machine so keep it “localhost”
xdebug.remote_port is the port on which the Eclipse listens for a connection from Xdebug (9000 is the default value)
Setting up XDebug in Eclipse
You would need an Eclipse with PDT installed
To simplify understanding, we’ll not start with a web application. We shall first start debugging an independent php script
Create the PHP Project with atleast one php file
Right click on the file and select Debug As > Debug Configuration
It will ask for setting the name of Debugging Configuration, PHP Server and the file
After configuring these parameters, click on the Debugger Tab and change the Server Debugger from Zend Debugger to XDebug
Apply these configuration and start Debugging by clicking on Debug button.
The script execution will pause(breakpoint) at the first line. This is the default configuration as shown in the above screenshot – Break at First Line
A Breakpoint is the line where the program execution will be paused by the debugger. The debugger then waits for you to signal when to continue execution. You can set multiple breakpoints in your application.
To add a breakpoint, you just have to double-click on the left of line number. Similarly, to remove a breakpoint, you have to double-click on the breakpoint.
When the program is in pause state you can inspect the variable values in that scope. Lets see how
In the above Screenshot, we have 4 views
- Debug – displays the call stack
- In Employee.php from the main section(line 84), constructor (__construct) for class Employee was invoked
- From that constructor (line 24), setName() was invoked
- And the program is paused at line 44 in setName()
- Breakpoints – The line numbers where breakpoints have been set
- Employee.php – the php file with breakpoint at which program is paused
- Variables – the values of the variables available in the scope
In the above diagram, At the right of the red square icon, there are some other actions i.e.
- Step Into (F5) – this button lets you step the execution into the function.
- Step Over (F6) – This means step one line ahead. If there is a function call at this line, then it shall be invoked and returned without pausing in the body of that function
- Step Return (F7) – If you stepped into a function and want to get out to the point of invocation of the function, just use step return
- Continue (F8). This will take the program to next breakpoint if it exist else it will complete the execution of the program
Lets have some assignment on Debugging
The code given below has been written to find out the smallest number and its position in the array .
The code has a bug and will give a wrong output — “Smallest is 1 at 9”
Try finding the bug using dry-running or actual running with print statements. Can you find the bug within 15 seconds .
<?php $a = array(5,9,2,1,22,100,6,77,20,40); $smallest = $a[0]; $pos = -1; for ($i = 0; $i < 10; $i++) { if ($a[$i] < $smallest) $smallest = $a[$i]; $pos = $i; } if ($pos != -1) echo "Smallest is $smallest at $pos "; else echo "Could not find the smallest "; ?>
Now lets use eclipse and Xdebug.
- Put a breakpoint at line no. 6
- And now debug the program using Eclipse and Xdebug.
- Program will paused at line no. 6.
- Use shortcut F6
- Debugger skipped line no 7 and moved to line no. 8.
- Currently, $i is 0, $pos = -1, $a[0] is 5 and $smallest is initialized to first element of the array i.e. 5
- According to the if condition, current element (i.e. 5) should be smaller than $smallest (i.e. 5) only then it should move inside the if.
- In this case the condition has failed.
- We realize that the statement $pos = $i is not enclosed inside the if condition, that is why $pos is reset in each iteration.
- Hence producing a wrong output.
Try this out and I hope that you will find it useful during your development cycles. It will surely make the debugging easier.
Conclusion
We learnt about Basic debugging functions, Logging and Debugging.
I hope this article will help you in improving your debugging skills and save a lot of your time. If it does, then do share some of your tips and knowledge too !
I intend to followup with an article on debugging PHP web applications, their performance profiling using XDebug, KCacheGrind and XHprof. Leave your comments if you are seeking any specific inputs on it.