Interactive PHP Debugging with PsySH

It’s 1:00 a.m., the deadline for your web application’s delivery is in 8 hours… and it’s not working. As you try to figure out what’s going on, you fill your code with var_dump() and die() everywhere to see where the bug is…

You are annoyed. Every time you want to try out a return value or variable assignment, you have to change your source code, execute your application, and see the results… In the end, you are unsure of whether or not you’ve removed all those var_dumps from the code. Is this situation familiar to you?

PsySH to the rescue

PsySH is a Read-Eval-Print Loop (or REPL). You may have used a REPL before via your browser’s javascript console. If you have, you know that it possesses a lot of power and can be useful while debugging your JS code.

Talking about PHP, you might have used PHP’s interactive console (php -a) before. There, you can write some code and the console will execute it as soon as you press enter:

Unfortunately, the interactive shell is not a REPL since it lacks the “P” (print). I had to execute an echo statement to see the contents of $a. In a true REPL, we would have seen it immediately after assigning the value to it.

You can install PsySH globally either with a composer g require, or downloading the PsySH executable:

Composer

composer g require psy/psysh:~0.1
psysh

Direct download (Linux/Mac)

wget psysh.org/psysh
chmod +x psysh
./psysh

Additionally, you can have it included per project with composer as you’ll see later in this article.

Now let’s play with PsySH a little.

./psysh
Psy Shell v0.1.11 (PHP 5.5.8 — cli) by Justin Hileman
>>>

The main help will be your best friend. It’s what will give you all sorts of commands and their explanations:

>>> help
help Show a list of commands. Type `help [foo]` for information about [foo]. Aliases: ?
ls List local, instance or class variables, methods and constants. Aliases: list, dir
dump Dump an object or primitive.
doc Read the documentation for an object, class, constant, method or property. Aliases: rtfm, man
show Show the code for an object, class, constant, method or property.
wtf Show the backtrace of the most recent exception. Aliases: last-exception, wtf?
trace Show the current call stack.
buffer Show (or clear) the contents of the code input buffer. Aliases: buf
clear Clear the Psy Shell screen.
history Show the Psy Shell history.
exit End the current session and return to caller. Aliases: quit, q

I defined the function say() and invoked it. Those two null you see are because neither the function definition nor its execution returned a value (the function echoes the value). Additionally, while defining the function, the prompt changed from >>> to ....

When I instantiated Foo, the constructor returned a reference to the object. This is why PsySh printed <Foo #000000001dce50dd000000002dda326e>. Now let’s see what is interesting about PsySH and objects.

>>> ls $foo
Class Methods: getA, setA
>>>

If by any chance you forgot which methods the class Foo has defined, you now have the answer. Have you used a Linux OS or Mac command line interface? Then you might be familiar with the ls command. Remember the -la options?

The script’s execution will be suspended, and we now have PsySH’s prompt to play with. I am passing get_defined_vars() as a parameter to Psy\Shell::debug() so I have access to all defined variables inside the shell:

This method is returning the object’s windowReference property, and as we saw from the ls -al command above, it is an instance of Acme\Patterns\Decorator\SimpleWindow. Of course, we could have just looked at how DecoratedWindow::__construct() works, but this is another way we can check.

Debugging with embedded server

Unfortunately, debugging through a webserver like Apache is not supported. However, we can debug our application using PHP’s embedded server:

The Development Server is now listening for connections on port 8080, so as soon as we request the decorator.php file through this web server (http://localhost:8080/decorator.php), we should see the following:

Debugging with unit tests

As a good developer, you should write unit tests for your code as proof that it is working as expected. In the project’s files you will find the tests folder, and if you have phpUnit installed, you can run the tests inside it.

If you are unfamiliar with phpUnit, do not pay too much attention to the code. In a nutshell, I’m setting up everything to test the TitledWindow::addTitle() method, and expecting to receive a non empty value.

So, how do we use PsySh to check what is going on? Just add the Shell::debug() method as we did previously.

Null value, no wonder the test failed… Let’s check the source code of TitledWindow::addTitle(). If we perform an ls command, we can see that we have that object’s method available through the $titledWindow object.

There is the bug. The method is echoing the value instead of returning it. Even though the application seems to work right, through unit testing and PsySH we discovered a defect and we can now fix it.

Conclusion

This article was not meant to be exhaustive in showcasing all the potential PsySH has. There are other cool features (like ‘doc’) that you should try out. PsySH alone may not be very useful, but if combined with other tools and your clever debugging powers, it can prove to be a valuable asset.