We all started somewhere. Personally I started trying to solve errors all by myself by just throwing different values to see what sticked to the wall. Shortly after, I knew what was the first step into what’s called “debugging”. Who knew…
What is debugging? One of the parts of writing software, is receiving a bug (an error), and then fixing it. Laravel and PHP itself are not too-strict, but when an error occurs, the normal procedure of the engine is to show what is called an Exception, along with the stack trace. The latter is a list of things the engine did to get the error. Today this is pretty much standard.
In this quick post I will describe five ways to know just that: what happened, where, and may be, a way to fix it. If you’re not n00b, you can skip the article.
1. Dump, and die (and debug)
When you encounter a problem in your application lifecycle, using
dd() is usually the fastest way to check what is happening before you hit the wall. You can issue any variable and then check it conveniently in the browser.
dd() helper stops the execution of the application, there is also the
dump() helper that will do the same but won’t terminate the application. Of course, depending on where you put it, you may or may not see what is dumped in your browser.
Starting with Laravel 6, you have access to the
ddd() helper, which you can see which will also show the debug page with more details about the application state and stack trace. It’s like Xdebug for free (more on that later).
2. Check your logs
Second rules of frameworks: check your logs— the first is “Read the docs”. By default, your application will write a log for every exception in the
storage/logs directory. Here you can check three key things:
- What happened.
- When it happened.
- The Stack trace, telling you how the application got there.
[2019-09-12 11:12:02] local.ERROR: Method App\Http\Controllers\PodcastController::listeners does not exists.
#0 [internal function]: Illuminate\\Routing\\Controller->__call('listeners', Array)
While the stack trace sometimes truncates variables, it won’t truncate the actual files and methods called. Unless you have installed a very unstable package that tries to calculate pi by quantum mechanics inside a tornado, you may want to focus on the files under the
App namespace, which are those which you have control. In the example above, the fix is easy: create the method in the class or change the call.
This may be enough for most scenarios, apart from the debug page you receive, which is a very friendly way to check the error.
3. Write in the logger
The first writes a string directly into the logger, while the latter gives you access to the Logger instance itself. For example, you can write a “debug” message, or an “error” message.
public function handle(Podcast $podcast)
'bitrate' => config('transcoder.bitrate.free_tier'),
'format' => 'mp3',
'output' => storage_path("transcoded/$podcast->id.mp3")
]) logger()->error('This should not have happened!'); // ...
The logger interface has several levels of messages, so in production you won’t get debug messages, but only critical ones like errors.
This can become handy to test queueable Listeners and Jobs, since these are in a process apart that you don’t have direct access. In any case, these still are bound to the exception handler of the application and write the errors inside your log files.
The only catch is to always pass a string. If you pass something that cannot be transformed to a string (like a plain class or an array) you will get an Exception.
4. Use Telescope or Debugbar
The first is an official package that allows you to check Requests, Exceptions, Jobs, Queues, and almost all the different features of your application. This is all offered in a different page of your application. One of the advantages of Telescope is that it can be enabled on production environments to keep an eye on your application when stuff happens.
Additionally, one of the handy features of Telescope is that you can use
dump() anywhere in your code and the contents of the dump will be rescued inside Telescope, while your Request proceeds as normal.
By contrast, Debugbar is a… well, a bar for debugging. It sits below your web views, and shows almost the same information that Telescope. This can become very handy on applications with a lot of views, logic and graphical interfaces, but this won’t help too much on SPA pages or APIs.
Of course there are more debugging packages out there, but these two are very complete packages to quickly check if something when fine, went wrong, or went completely FUBAR.
5. Connect to Xdebug
If none of these solutions makes your life easier, and you need something more close-to-code, then Xdebug is the tool you need.
Installation it’s not just plug-and-play, it requires to edit some PHP files and let it connect to your IDE, which you should be using by now instead of a plain text editor, or a browser extension to connect both properly. The payoff is having access to a very powerful tool that you may not live without since it can give you a lot of details.
One of the key advantages of Xdebug is something like “live tracing”. You can set a point in your code where Xdebug will pause the execution of the application, and show the application state in your IDE, allowing you to see the what is happening. From there, you can intercede, stop and continue, among other things. This has saved me several times in the past where something that should have happened didn’t, which wasn’t an error.
When set up correctly, you can even debug your Tests, no joke. In PHPStorm, you can set a breakpoint in your code, run your test, and you will have full information about the code running. Others IDEs may offer something similar, so RTFM.
Xdebug comes with some performance penalties, like with any other debug software, but most of them are negligible unless your application is very, very, very weird. Also, Xdebug on production machines is usually absent—its considered between security risk and performance hog, but you may set up an internal “staging” version of the application with Xdebug enabled just in case.
And that’s it. You’re pretty much covered from all angles.