In the previous article from this series
(A few words about debugging – Part III) we looked at the good debugging practices. Today we will present some real life examples to show you how this all works in practice. Let’s go!

4) A sample debug session

The errors that probably are the most difficult to fix are the exceptions thrown by the framework’s libraries. Very often error messages are scanty, the code looks correct and it’s not entirely clear what caused the issue.

Usually the reason lies in the code that calls a given framework function (directly or indirectly) with, for example, an incorrect parameter. The parameter is therefore the cause of the error and you need to find where it occurs.

If you are not the author of the code, the quickest way is to look through the stack-trace to trace the incorrect value.
Example:

function play() {
  $ids = array();
  if (rand() < 0.5) $ids[] = 5;
  if (rand() < 0.2) $ids[] = 15;
  if (rand() < 0.1) $ids[] = 2;
  $model = load_random_element($ids);
  if ($model) {
    echo "You have won a " . $model->name;
  } else {
    echo "You did not win anything";
  }
}
// Picks random element id
// from array of ids and loads
// element by this id

function load_random_element($ids) {
  if (!is_array($ids)) {
    throw new Exception("...");
  }
  return Model::load($ids[floor(count($ids) * rand())]);
}
class Model {
  static function load($id) {
    if (!$id) {
      throw new Exception('Model ID cannot be empty');
    }
...
    return $model;
  }
}

We have one Model class, an auxiliary function drawing from the array of IDs and loading the model with the drawn ID, and a function responsible for the drawing itself and providing the information to the user.

And we have this random error:

image6

Debug is like playing cat and mouse: you know that something is not working properly, you frequently know where the error occurs, but you don’t know what causes it.

There might be many reasons for the error:

  • syntax error;
  • wrong/prepared data input by the user;
  • incomplete handling of incorrect arguments.

Usually you can safely assume that there are no errors in the very framework and you should look for the errors in your own files.

We can conclude the following from the error messages that we received:

  • we refer to an array element that doesn’t exist in the load_random_element function (Notice);
  • the script has stopped due to the unhandled exceptions (Fatal Error);
  • the load method of the Model class object has thrown the following exception: “Model ID cannot be empty”.

As you can see in the stack-trace, the script has stopped in the “load” method of the “Model” class. It means that the method’s argument “$id” is empty. The “$id” parameter is drawn from the array of $ids which is the parameter of the “load_random_element” function. Let’s assume that at first glance there isn’t anything wrong with this function and put “var_dump($ids); die;” right after the function’s definition:

(...)
function load_random_element($ids) {
var_dump($ids);
(...)

You should see the following output from the var_dump when the script is executed in the browser:

array (size=0)
empty

It means that the array is empty for some calls and it draws “null” when drawing from an empty array. This is why the exception occurs. To get rid of it, you just need to check whether the array is not empty by replacing:

if (!is_array($ids)) {
with
if (!$ids || !is_array($ids)) {

Summary

Errors in the code happen – how fast you can find and fix them is just a matter of experience. In the case of applications with multiple dependencies between their classes/functions the debug is more difficult and time-consuming.

One of the ways to avoid errors is so-called test-driven development, where you write tests to ensure that every element of your application is correct. We will show you how it works in practice in one of the next articles, so stay tuned!