PHP code, about readability and performance
Tags: php, performance, readability, recursion
Published: 2017-07-27 14:41:36

---
title: PHP code, about readability and performance
published: true
description: A reflexion about performances, readability and simplicity of the PHP code.
tags: php, performance, readability, recursion
---

Lot of my coding time is spent to improve performance and find bugs, PHP give much freedom for coding and this often evolve in bad habits, therefore need pay attention for write fast and efficient code.

Write fast code for me means that some times I must do a choice between readability, short code, simplicity and performance.

As example I can report my experience with the [recursion](https://en.wikipedia.org/wiki/Recursion_(computer_science)). Recursion, informally when a function calls itself, can be used for solve problems and create algorithms with a few lines of code.

This is good, but with PHP could be a bad thing because **call a user-defined function is expensive** in term of time.

## The problem

Write a dependency injection resolver. I need a method that create a map of the dependencies and store it inside an array.

First I used the recursive approach as fastest to implement. When I did profiling, i saw that most of the execution time was used to resolve the class dependencies. The recursion is too expensive and need to rewrite the code.

#### Solution

After a fast search on internet, I decided to use **iterative** approach that compared to **recursive** need more code but is faster.

As recursive:

```
<?php

/**
 * Create a dependencies map for a class.
 *
 * @param int $level Depth of dependency
 * @param string $class Class to build dependencies
 */
private function buildTree(int $level, string $class)
{
    //initialize array
    $this->tree[$level][$class] = [];

    //get parameter from constructor
    $param = (new \ReflectionClass($class))->getConstructor()->getParameters();

    //loop parameter
    foreach ($param as $key => $value) {

        //if there is parameter with callable type
        if ($value->hasType() === true && class_exists((string) $value->getType())) {

            //store dependency
            $this->tree[$level][$class][] = $value->getClass()->name;

            //call recursive
            $this->buildTree($level + 1, $value->getClass()->name);
        }
    }
}

```

And as iterative:

```
<?php

/**
 * Create a dependencies map for a class.
 *
 * @param string $class Class to build dependencies
 */
private function buildTree(string $class)
{
    //set start level
    $level = 0;

    //create stack
    $stack = new \SplStack();

    //iterate
    while (true) {

        //initialize array if not already initialized
        if (!isset($this->tree[$level][$class])) {
            $this->tree[$level][$class] = [];
        }

        //get parameter from constructor
        $parameters = (new \ReflectionClass($class))->getConstructor()->getParameters();

        //loop parameter
        foreach ($parameters as $param) {

            //check if argument is already stored
            $notAlreadyStored = !in_array($param, $this->tree[$level][$class]);

            //if there is parameter with callable type
            if (class_exists((string) $param->getType()) && $notAlreadyStored) {

                //push values in stack for simulate later recursive function
                $stack->push([$level, $class]);

                //store dependency
                $this->tree[$level][$class][] = $param;

                //update values for simulate recursive function
                $level++;
                $class = (is_object($param->getClass())) ?
                    $param->getClass()->name : null;

                //return to main while
                continue 2;
            }

            if ($notAlreadyStored) {
                //store dependency
                $this->tree[$level][$class][] = $param;
            }
        }

        //if stack is empty break while end exit from function
        if ($stack->count() === 0) {
            break;
        }

        //get last value pushed into stack;
        list($level, $class) = $stack->pop();
    }
}
```

As you can see, at first look, iterative code is longer and more complicated than recursive. In details, main differences are only a while loop and a [LIFO](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) data structure for simulate the call stack.

#### Benchmark

Returning to profiling of the code and to performance, differences in execution time between previous pieces of code are very significative. The speed gap, grows with the number of function calls.

I do a little benchmark using php microtime() and this is the result:

|  Calls | Execution Time Iteractive   | Execution Time Recursive |   Fastest  |
|:------:|:---------------------------:|:------------------------:|:----------:|
|    1   |             100%            |         30% - 50%        |  Recursive |
|   10   |             100%            |        180% - 210%       | Iteractive |
|   100  |             100%            |        300% - 450%       | Iteractive |
|  1000  |             100%            |       700% - 1100%       | Iteractive |
| 10000  |             100%            |        600% - 700%       | Iteractive |

In benchmark I have simulated a class that depend by other classes. Example Class A depend from B, B from C, C from D, D from E etc. Total nine nested classes.

Benchmark was executed with Virtual Box, Ubuntu Server 16.04.2, Apache/2.4.18, php 7.1.7 with mod-fpm. Virtual machine: Intel(R) Core(TM)2 Extreme CPU X9100, 2 Cpu max 40% and 512Mb of Ram, SSD. Benchmark ran 10 times and recursion values are averaged.

## Conclusion

In conclusion, when need to do a choice between "how the code is written" and performance, for me it's best have more execution speed and less code simplicity /readability. Can help in this case, leave more detailled comments (what and because, not only because) for not forget what the code do.

Of course, the previous consideration does not mean that you do not have to follow the good code practices.