Other Articles in the SeriesPart One: Introducing xdebugPart Two: Tracing PHP Applications with xdebug Part Three: Profiling PHP Applications With xdebug Part Four: Debugging PHP applications with xdebug Part Five: Creating Code Coverage Statistics with xdebug Welcome to the second installment of our five-part series of articles on xdebug, the PHP developer‘s swiss army knife extension. The installation of xdebug and its basic features were covered last week. This week, we will explore the tracing feature of xdebug. As programs, especially object-oriented ones, become more and more complex, the individual code blocks become smaller and smaller. Small code blocks make a program easier to maintain, since changes and additions can be introduced without changing existing code. If you look at an object-oriented PHP program for the first time, however, it seems that the program never does any actual work, but just comprises of a seemingly endless series of delegations. Though it may sound awkward, this is a sign of quality of object-oriented code. Each piece of code should do exactly one thing and different concerns should be separated. As a rule of thumb, the source code of one method should fit on the screen without scrolling. These small code bits make software maintainable, but on the other hand it becomes very difficult to understand the actual control flow of a program. While it is rather easy to understand a single class or method, one can have a really hard time trying to figure out the control flow of a complex object-oriented application just by looking at the code. We could put numerous Creating a trace logInstead of manually adding logging code to the program code, we can have xdebug create a trace log while the program executes. A trace log is a list of every function and method call a PHP script has performed. The advantage is that every call appears in the trace log, not just the information we chose to log explicitly. On the other hand, the longer a trace logs get, the harder to read it becomes. A trace log will usually differ with each program run, because the program‘s execution path depends on the input data, and the input data fed to the program will probably vary from request to request. Imagine a web application that executes a command issued by a GET parameter. Depending on the command, different code is being executed, resulting in completely different trace logs for each run. While looking at a trace log helps us understand the control flow of a program by showing one execution path, is is virtually impossible to visualize all execution paths of that same program, unless the program is really simple. One But let us now get into creating a trace log. xdebug supports two different trace log formats. By default, trace logs are created in nicely formatted way so that the human user can easily read them. If you want to process the trace logs with another computer program, you should configure xdebug to log in the computer-readable format. The computer-readable format is easier to parse, because in contains no fixed size columns. If you are using auto prepend scripts that you want to show up in the trace log, or want to create a full trace log of every script that is run, you can put
xdebug.auto_trace=On xdebug.trace_output_dir=c:\data into php.ini. As always, remember to restart your web server after changing php.ini. The second setting defines the path where xdebug will store the trace logs. This path defaults to /tmp which is a good choice on Unix, but calls for trouble on Windows, since the directory c:\tmp (provided that the c: is the current drive) usually does not exist. So you either need to create this directory or specify another existing directory, otherwise xdebug will not be able to create trace logs since has nowhere to store them. Because trace logs get large, the are not kept in memory, but are written to the disk. As you can imagine, the application will run a multitude slower with tracing enabled since every function and method call at PHP level results in a line written to the log. Please note that it is not possible to start tracing at script runtime with
because auto prepend scripts are executed before your the main script is even started, which would prevent the prepend script to be traced. Tracing a part of an applicationAs trace logs grow to a considerable size quickly, it is a good idea to only create a trace log for the "interesting" part of your application instead of - for example - creating a trace log of the application‘s initialization process over and over again. Let us have a look at how to create a trace log of a simple recursive function, the factorial function, that starts and stops trace logging at runtime. If you have already activated tracing in php.ini, you will see a warning telling you that tracing is already active for the script. <?php xdebug_start_trace(‘c:/data/fac.xt‘); print fac(7); function fac($x) { if (0 == $x) return 1; return $x * fac($x - 1); } xdebug_stop_trace(); ?> As you can tell from the path and filename of the trace log, I have run this example on Windows. If you work on Unix, you must use a different file name, of course. The function TRACE START [2007-10-26 12:18:48] 0.0068 53384 -> fac() C:\www\fac.php:5 0.0069 53584 -> fac() C:\www\fac.php:10 0.0069 53840 -> fac() C:\www\fac.php:10 0.0070 54096 -> fac() C:\www\fac.php:10 0.0070 54376 -> fac() C:\www\fac.php:10 0.0071 54656 -> fac() C:\www\fac.php:10 0.0072 54936 -> fac() C:\www\fac.php:10 0.0072 55216 -> fac() C:\www\fac.php:10 0.0073 55392 -> xdebug_stop_trace() C:\www\fac.php:13 0.0237 55392 TRACE END [2007-10-26 12:18:48] On each line, the first column shows the total execution time. The second column is the amount of memory the script was consuming at the time. The last column shows the file, line and function name. xdebug indents each function call according to the call stack level for better readability. If you want xdebug to show an additional memory delta column in the trace log, add
to php.ini. The memory delta is the difference between the memory size in the current line and the previous line. You can configure this setting at runtime with The function The following screen shot shows an HTML-formatted xdebug trace log:
Adding more information to the trace logWe can also configure xdebug to log the parameters that were passed to a function. This is very helpful to better understand the program‘s control flow, since you can see the values the program deals with.
Logging parameters in a trace log is controlled by the configuration setting Here is an excerpt of our trace log with the logging of function parameters activated: 0.0033 54320 -> fac($x = 7) C:\www\fac.php:6 0.0034 54432 -> fac($x = 6) C:\www\fac.php:11 Let us add even more information. Using
we can configure xdebug to also log the return values of each function. This makes the trace a little more difficult to read, but looking at the log of our factorial function, you can see how each recursively calculated factorial is being returned: TRACE START [2007-10-26 12:30:04] 0.0133 55704 +48 -> fac($x = 7) C:\www\fac.php:8 0.0133 55840 +136 -> fac($x = 6) C:\www\fac.php:13 0.0134 56096 +256 -> fac($x = 5) C:\www\fac.php:13 0.0134 56352 +256 -> fac($x = 4) C:\www\fac.php:13 0.0134 56632 +280 -> fac($x = 3) C:\www\fac.php:13 0.0135 56912 +280 -> fac($x = 2) C:\www\fac.php:13 0.0135 57192 +280 -> fac($x = 1) C:\www\fac.php:13 0.0135 57472 +280 -> fac($x = 0) C:\www\fac.php:13 >=> 1 >=> 1 >=> 2 >=> 6 >=> 24 >=> 120 >=> 720 >=> 5040 0.0140 57648 +176 -> xdebug_stop_trace() C:\www\fac.php:26 0.0140 57648 TRACE END [2007-10-26 12:30:04] As you can see, we have also turned on Naming the trace logUntil now, we have explicitly defined the name of our trace log file. This does not always make sense, though. If you need separate trace logs depending on input data or the application state, for example, it is better to have xdebug automatically pick a name. xdebug can pick a name for your trace log, regardless of wether you use the The file name of an xdebug trace always starts with trace. and has the extension .xt. The name part between the two dots defaults to the CRC checksum of the working directory. By the setting
Using a clever combination of these format specifiers, you can have xdebug create a number of trace logs and still keep them separate even in complex scenarios like with virtual hosts or concurrent request. In most cases, you will want to create a trace log for one single run of a script. Therefore, xdebug overwrites existing trace logs of the same name by default. You can configure xdebug to append to an existing file by setting
in php.ini. This might be useful when you tunnel all requests of your application through one If you need to know at script runtime which trace log name xdebug has chosen, you can call the function ConclusionThe function tracing feature of xdebug is very useful. You can create logs in your application without adding a single call to a logger function. Since all function calls are logged, you will always have the relevant information in the log file, whereas with a explicit logger function, you might end up adding more and more logger calls until you finally have the relevant information in the log. You can use tools like You should never activate trace logging on a production site, because that would absolutely kill your performance as one line has to be written to a file for every function call in your PHP script. That said, you should never install xdebug on a production server, not because it is not stable or insecure, but just because you don‘t want somebody to accidentally turn on trace logging, profiling, or even debugging. This concludes this‘s weeks dose of xdebug, thanks for joining in on the second installment of this five-part article series on xdebug. Next week we will explore how to profile PHP applications with xdebug. Profiling an application is the first step in optimizing it, because you need to know where your application spends most time, before you can figure out how to make your application faster. So, make sure you check back here next week for the third part in this series of xdebug articles. Until then: Happy tracing - with xdebug enabled, of course. |
|