Benchmarking Laravel Helpers: A Performance Comparison
Tags: laravel, performance, testing, benchmark
Published: 2023-04-30 20:32:47

Laravel is one of the most popular PHP frameworks available today, offering a vast array of built-in **helpers** to make developers' lives easier. However, when it comes to optimizing the performance of your Laravel application, it's essential to know which helper functions work best in different scenarios.

**What are Laravel helpers?**

Laravel helpers are simple functions that provide a convenient way to perform common tasks. They are included in the framework and can be called from anywhere in your application. Helpers are designed to be lightweight and easy to use, but their performance can vary depending on the task at hand.

---

**How it started?**

It all began with a simple pull request where I suggested a small change to the usage of a Laravel helper function, in order to make it a bit cleaner. In response, I was told that the suggested change was actually slower, which I agreed to.

But that opened a question for me -  _how much slower it actually is?_ This question piqued my curiosity and I decided to run some benchmarks to see just how much slower it was. Some of the results were surprising to say the least.

---

In the following section, we'll dive into benchmarking Laravel helpers, outlining the steps I took to test and compare their performance against some alternative methods.

**Creating a benchmark project**

The first step was to create a Github repository - [laravel-benchmarks](https://github.com/mujiciok/laravel-benchmarks) - to host the benchmarking code. In order to benchmark Laravel helpers, I created a Laravel project using [Laravel v10.9](https://laravel.com/docs/10.x) and [Sail](https://laravel.com/docs/10.x/sail). To run benchmarks on your local machine, follow the instructions from the Github repository.

**Creating a benchmark class**

To ensure consistent and accurate benchmarking, I created a class for each Laravel helper benchmark that I wanted to run. Each class contains some methods which will be tested and have benchmarks. I chose to test each Laravel helper against alternative methods, like regex functions or other native  PHP functions.

**Writing unit tests**

For each benchmark class, I wrote a corresponding unit test, which runs on 10, 100, 1.000, 10.000, 100.000 and 1.000.000 iterations for each tested method. I used Laravel's [Benchmark](https://laravel.com/docs/10.x/helpers#benchmarking) class to get average time, in nanoseconds, for each method. 

```
    public function benchmark(string $haystack, string $needle): void
    {
        $logData = [];
        // a mapping of method names from BenchmarkService to output table rows names
        $methodsData = $this->getMethods();
        // a mapping of number of iterations to output table column names
        $iterationsData = $this->getIterations();
        // the tested service 
        $service = $this->getBenchmarkService();

        foreach ($methodsData as $methodName => $rowHeading) {
            foreach ($iterationsData as $iterations => $columnHeading) {
                // this Benchmark::measure will return the time spent on each method call for a given number of iterations
                $logData[$rowHeading][$columnHeading] =
                    Benchmark::measure(fn() => $service->{$methodName}($haystack, $needle), $iterations);
            }
        }
        
        // the function that converts received data into a README table format
        $this->logTable($logData);

        $this->assertTrue(true);
    }

```
I also included a validation test to ensure that all methods in the benchmark class had the same functionality (at least for the tested cases).

**Logging and sharing results**

After running the benchmarks, I output the results to the Laravel's log file, which I then copied and inserted into a README file for each benchmark class. To present the benchmarking results in a clear and concise format, I created a small trait that converts the test results into a table format that is compatible with the README file (_see example below_).

|               |       x10 |       x100 |      x1_000 |      x10_000 |      x100_000 |         x1_000_000 |
|---------------|-----------|------------|-------------|--------------|---------------|--------------------|
| Str::endsWith | 0.0024561 | 0.00190203 | 0.001714902 | 0.0017067036 | 0.00171911167 | 0.0016987282409992 |
|    preg_match | 0.0046733 | 0.00142272 | 0.001386046 | 0.0014287932 | 0.00145006377 | 0.0014515480600005 |
| str_ends_with | 0.0013112 | 0.00099935 | 0.000994674 | 0.0010140036 | 0.00100748115 | 0.0010328349029996 |

To make it easy for others to navigate the benchmarking results, I included links to each benchmark class README file in the main README for the repository.

---

I hope this article has been helpful in your quest for optimal performance in your Laravel applications. Don't be afraid to test the project locally and experiment with your own benchmarks. You're also welcome to suggest new benchmarks, test cases etc. Who knows, you might discover some surprising results (_please share them_) that will help you write even more efficient code!

Happy coding! 
:)