- Harness PHP 7’s Performance Boosts: Part 1
- PHP 7’s Performance Boosts :More Possible Optimizations
In part 1 of the series by Andrew Caya, you learned how to harness PHP 7’s performance boosts using some of its key optimizations, including strict typing, immutable and packed arrays, and memory allocation. In part 2 of the series, you will identify more such possible optimizations.
Identifying more possible optimizations
When optimizing an application, you will start by identifying the most time-consuming functions, especially along the application’s critical path. Most of those functions will be I/O functions as these are always the most expensive operations for a computer to execute. Most of the time you will see the possibility to optimize loops and reduce the number of system calls, but you will soon realize that I/O operations remain costly no matter what optimizations you wish to bring to them. Sometimes, though, you might run into very slow PHP structures that can simply be replaced with faster ones, or you may realize that poorly designed code can easily be refactored to be less resource-hungry, such as when replacing a dynamic structure with a simpler static one.
Indeed, dynamic structures should be avoided unless absolutely necessary. You’ll now have a look at a very simple example. You can program the same functionality four times, but with three different approaches: functional and dynamic, functional and static, and finally, structural and static.
Functional and dynamic approach
Start with the functional and dynamic approach:
// chap3_dynamic_1.php $start = microtime(true); $x = 1; $data = []; $populateArray = function ($populateArray, $data, $x) { $data[$x] = $x; $x++; return $x <= 1000 ? $populateArray($populateArray, $data, $x) : $data; }; $data = $populateArray($populateArray, $data, $x); $time = microtime(true) - $start; echo 'Time elapsed: ' . $time . PHP_EOL; echo memory_get_usage() . ' bytes' . PHP_EOL;
This code creates an array with 1,000 elements by calling the same closure recursively. If you run this code, you’ll get the following result:
Time elapsed and memory consumed when running the script programmed with the functional and dynamic approach
Now have a look at the results of running this script using Blackfire.io:
The profiling report when running the script programmed with the functional and dynamic approach
Functional and static approach:
Now code the same functionality but in a more static fashion with a classic named function instead:
// chap3_dynamic_2.php $start = microtime(true); $x = 1; $data = []; function populateArray(Array $data, $x) { $data[$x] = $x; $x++; return $x <= 1000 ? populateArray($data, $x) : $data; } $data = populateArray($data, $x); $time = microtime(true) - $start; echo 'Time elapsed: ' . $time . PHP_EOL; echo memory_get_usage() . ' bytes' . PHP_EOL;
If you execute this version of the code, you’ll obtain the following result:
Time elapsed and memory consumed when running the script programmed with the functional and static approach
Running the script with the Blackfire.io profiler yields these results:
The profiling report when running the script programmed with the functional and static approach
Structural and static approach:
Finally, program this functionality again but in a very structural and static way using a for loop instead of tail-calling the function recursively:
// chap3_dynamic_3.php $start = microtime(true); $data = []; function populateArray(Array $data) { static $x = 1; $data[$x] = $x; $x++; return $data; } for ($x = 1; $x <= 1000; $x++) { $data = populateArray($data); } $time = microtime(true) - $start; echo 'Time elapsed: ' . $time . PHP_EOL; echo memory_get_usage() . ' bytes' . PHP_EOL;
Here are the results after executing this latest version of the code:
Time elapsed and memory consumed when running the script programmed with the structural and static approach
Here are the results of profiling this version of the script with Blackfire.io:
The profiling report when running the script programmed with the structural and static approach
The results clearly show that the structural approach is the fastest. If you now go a little further down the structural route with only a hint of functional programming and try using a generator to create the array iteratively, you should not be surprised by the high performance results that you’ll get. Here is the last version of the code:
// chap3_dynamic_4.php $start = microtime(true); $data = []; function populateArray() { for ($i = 1; $i <= 1000; $i++) { yield $i => $i; } return; } foreach (populateArray() as $key => $value) { $data[$key] = $value; } $time = microtime(true) - $start; echo 'Time elapsed: ' . $time . PHP_EOL; echo memory_get_usage() . ' bytes' . PHP_EOL;
This is the result when running the latest version of the code:
Time elapsed and memory consumed when running the script programmed with a very structural and static approach
Here are the results with Blackfire.io:
The profiling report when running the script programmed with a very structural and static approach
The results clearly show how this last version of the code really outperforms the other ones. Indeed, PHP is still a very structural language as its compiler still does not fully optimize tail-recursion calls and does take less time to complete the execution of a program if it is coded in a structural way.
If you liked this article, you can refer to Andrew Caya’s Mastering The Faster Web with PHP, MySQL, and JavaScript. This book will help you boost the performance of any Web application using advanced PHP, SQL and JavaScript techniques and make it part of what has come to be known as the Faster Web.
In case you are interesting in knowing about RESTful web services development in PHP and Laravel(or Lumen) then you may like Building RESTful web services with PHP7 as well.