Here you can find a concept model about debugging PHP, with some details on use of Vim.
The basic idea of debugging
This article is a general introduction to php debugging, with some details for debugging from within Vim.
First, all the instructions you write in your program (the php statements) are also generally called "text", "script", "source" or "code". Also the term "program" is used, but this term may refer to more that just "sources".
To give a casual (informal) introduction of the concept, debugging is a way to execute your program line by line, one at a time, while you are watching the source code so you can see what line the program is currently at. At any time during debugging you can see (or inquire for) values for the program variables that are in scope for the current line of code, as well as the list of functions that are currently being executed. Running your program line by line is also referred to as stepping through the code lines.
For this to work your program is said to be run under the control of another program, the debugger, that takes care of internal commands needed to pause (suspend) your program after each line, to enquire about variables values and functions list, and to resume your program in order to reach the next line. The program under control of the debugger is also called the debugee (or the inferior). Most of the times the debugger is the one to start and stop the debugge, as required by the user. A debugger may also suspend the debuggee at any chosen point in the source code, not necessarily at every line. Such chosen points are called breakpoints.
During debugging the user may interact with any of the two programs (debugger or inferior) as needed, but remember the debuggee will be suspended (paused) between source lines for the most of the time.
By this definition the debugger must be, at least somewhat, aware of the programming language that you use to write your program. Although here we talk about debugging scripts written in php language, almost all programming languages have a debugger, which is an important tool for programmers. Some debuggers understand multiple languages.
This definition also means the debugger must know of, and must be able to open, the source code of the program (the script file), so you can see the current line in there. While this requirement will appear self-evident for php scripts, it is an important aspect for other languages (like C++, Java, Pascal...) in which the program source files are first translated (compiled) into an executable file, which is then used to run the program even without the original sources.
Also by this definition, debugging a program implies running the program. That is, if the program is supposed to delete a file when it runs, it will delete the file when you debug it, too. Or at least it might, if and when it reaches the relevant line of code for that. Debugging a program means running it under control, but it still means running it.
Actually, in case of php programs, the debugger does not have to be another program, because php itself can do the debugging. But you should still make a distinction between:
- the script, as your program, and
- php itself, as the interpreter and debugger.
The whole purpose of debugging is to help find out where exactly in the program does an error appear, or where does the course of execution deviate from the course you intended. That is, to help you find out the cause of any program defects you may encounter while writing your code.
To make a little drawing, lets consider the symbol "=>" to mean that one program controls another is some way (debugging or not). Than we could represent the debugger and debuggee like:
debugger => debuggee
And if we consider that the user can interact with both of them, and we want to use a line like this <----> to represent an interface for communication or interaction, we can do that like:
user <----> debugger => debuggee <----> user
In this representation the user is included twice, but you should think of both occurrences as the same user.
Remote debugging allows one to use one computer to debug a program (or script) that is running on another computer. While this is not commonly used in other languages, in php you might run into it.
The two machines should be connected over a network, so they can communicate with each other. In this model, the "debugger" is no longer just one program with the role to control another, but is now made of two programs, one for each of the machines involved, and that communicate over the network. The two programs have different roles now:
- one has the role to control the debuggee
- one has the role to receive input from the user and display the source code.
The first is called the debug server, the other is the debug client.
While most debuggers offer remote access as an additional feature, for PHP this is the main model (actually the only model, as far as I know) used to setup your debugging configuration. And it makes sense to do so, since many PHP scripts are web pages that run on the web server, to which you might want to connect remotely.
Of course you can configure a single computer to play both roles, the remote and local sides, and than the remote debugging mechanism is no longer appearent, but you will note that the concepts of debug server and debug client are still there, and the TCP connection on port 9000 (by default) is still used.
The two processes follow a specific protocol to communicate, named DBGp. This client-server approach allows for the development of more than one debug client program, for the same debug server. XDebug comes with source code for a command-line client, but you can also find a GUI client for Windows.
This approach also allows for debugging to be integrated with other software products, like Vim, Eclipse, Netbeans, etc, that need only know the DBGp protocol. The protocol even allows for proxies that act as an intermediary and forward traffic between the debug server and debug client.
The downside of this model is that it is a little difficult for users to configure it.
We can now represent the remote debugging model in a drawing like this
________________________ ____________ | | | | user <----> |debuggee <= debug server|<----DBGp---->|debug client| <-----> user | | | | +------------------------+ +------------+ MACHINE 2 MACHINE 1
Usually the user would not interact with the debug server directly, and may not even interact with the debugge.
With remote debugging, you can see again the need for the source files to be available. The script being debugged resides on MACHINE 2 in the diagram, but you need it also on MACHINE 1, so you can see what line of code the program has currently reached. Most debuggers require that you have a copy of the source files on MACHINE 1 for this to work, but it is conceivable for the debug server and debug client to arrange the transfer of a copy of the source files automatically when needed, so the user needs not worry about it.
Remote debugging for web pages
Think of a web page you just wrote in php, that is now available on a web server. The web server is perhaps just another computer in your company network. Now you decide you want to debug the php web page on the server.
For this, you imagine that you must use some remote debugging, becase the web page resides on the server, as does php (installed there), while you work from your desktop computer.
The web page is just a php script, of course, but now you must think that php runs under the control and command of the web server. So you now have only indirect control to it (and your php script), through the web server.
Really you do not have direct access to the web server, either. But when you load a page in the web browser (Firefox, Internet Explorer, Google Chrome, Safari, etc...), the web browser is a client for the web server carrying the page. It is a client in the sense that it connects to the server, requests the page by its adress (URL), the server responds to the request with the page content, than the client closes the connection.
To provide the page contents, the web server starts the php script for the page, and waits for the script to run, in order for it to provide output. The script output is then used as the page content and sent to the client.
In short you use the web browser to start the php script. You only have to load (or refresh/reload) the page in the browser, to get the php script started on the server. The same mechanism is used to start debugging. This is the indirect control you have on php installed on the server. In a way, to debug the script is equivalent to running the script, with some debugging option enabled. Script output during debugging is sent to the web browser as the page content like it is sent during a normal run of the script. The web client essentially does not not know if the page is being debugged or not.
To start debugging with a page request in this way, you may want to install the appropriate XDebug plugin for your browser, and make sure the "debug" button it provides on the toolbar is "on" when you load your page.
Other than using the browser as the indirect means to start the script, debugging the page on the web server is no different than remote debugging as presented previously. The web server, where php and your scripts are running, is the debug server, and your desktop computer will be the debug client.
However you have now added a new machine to the model, the machine with the web browser, and a new program. the web server that controls php. Again, you may use the same desktop computer for both the debug client and the web browser, but the conceptual model, saying the web browser runs on a potentially different machine, still stands. Perhaps a diagram will help visualize the model:
___________ ___________________________________________ ____________ | | | (php) | | | | | | debugger server | <---DBGp---> |debug client| |web browser|<---HTTP--->|web server => debugger server | | | | | | debugger server => php script| | | +-----------+ +-------------------------------------------+ +------------+ MACHINE3 MACHINE2 MACHINE1
Here the debugger server (normally php) is connected to 3 components:
- it runs under the web server which controls it
- it receives input as commands from the debug client
- it controls the php script as the debuggee
All this might look complicated at first, but it is only of use as a concept model, and once you can get a debugging session started you don't need to think about it any more. Also you may think of the web browser and web server together as a complicated way to do the simple job of starting the php script, and than stick to the simple remote debugging model.
Configuration and usage
One thing to note is that in a client-server model you might expect the client to connect to the server. But in case of PHP debugging, the server initiates the connection, and the client just waits to receive one. So you should expect to start debugging by telling your text editor to wait for an incoming connection.
Now in order to break into and to control a PHP script line by line for debugging, the debug server must be PHP. Actually it is a PHP extension, which is not provided with PHP by default, so it needs to be downloaded and installed. See XDebug.
To start a PHP debugging session you need to start both the client and the server, so you need two steps:
- Start the client (Vim) and have it wait for an incomming connection.
- Start the PHP script and have the server (XDebug) start a debugging session and initiate the connection with the client.
For security reasons the XDebug extension will not allow debugging and remote connections by default. So you need to edit some XDebug settings in your php.ini file to enable remote debugging. See the XDebug documentation for that.
In a local network not accessible from the internet you might want to enable xdebug.remote_enable and xdebug.remote_connect_back, and then you could start debugging from any computer on your network.
To start debugging, more precisely to request a debugging session for a certain web page, you should simply display the page in the browser and add the XDEBUG_SESSION_START query parameter to the URL (or use a similar cookie) that XDebug looks for on every page. Several debug clients can open your web page and send this parameter automatically when you start debugging, but you can also add it manually to an URL.
By installing the appropriate Vim script you can get a debug client right in your text editor, and debug your files from Vim. There are several such scripts, most of them for Linux, and as of now they are not necessarily of good quality. You can search Vim scripts for "XDebug" to find them.
Such a script will most likely wait for a new debugger connection, and let you open the page you want, when you start debugging.
For this reason you should install the XDebug browser extension (for the browser used). This will allow you to debug the next page you load by clicking a button on the toolbar.
Of course PHP debugging is not only for web pages, but for command line PHP scripts also. Note that such a script may well be a GUI application, it is only called "command line"-script to distinguish it from a web page. To request debugging for these, you have to set the XDEBUG_CONFIG environment variable before you start PHP. When PHP starts and the XDebug extension finds this environment variable, it will try to connect to a listening debug client on the TCP/IP port given in php.ini.
Now an IDE that supports PHP debugging will try to do both steps (start listening and start the script) with one keyboard shortcut or one mouse click, but when using Vim you will have to perform these separately:
- Start listening for connections (usually press F5).
- Start your PHP script and request debugging with XDEBUG_SESSION_START or XDEBUG_CONFIG.
This article includes only general information about PHP debugging model. You shoud see the documention for XDebug and for the debug client (Vim script) to find the actual configuration you will need to do.
Do not be surprised to find the PHP debugger to be less of a featured software or not as stable as you would expect a classic C/C++ debugger for example. I also find that by trying to evaluate a sufficiently malformed expression I will prematurely terminate the debugging session and my script execution. A debug client like script 4009 can try to get around that with a pair of nested try/catch statements included in the eval command, but it is still not a good solution and does not always work.