A developer's guide to optimizing PHP performance
With its open-source nature, PHP has evolved into one of the most popular languages among web developers. According to w3techs, 78 percent of websites across the globe use PHP as their server-side language. Even amongst the top 1,000 ranked sites, PHP is dominant, being used by more than 50 percent of them.
While PHP is efficient and versatile, it also comes with a myriad of configurations and options, and choosing the wrong settings or functions could result in catastrophic performance and scalability problems.
In this blog, we'll discuss some of the commonly known bottlenecks in PHP performance along with the tools and techniques to measure and optimize them.
Understanding performance bottlenecks
Different performance bottlenecks can occur at different stages of development. At the early stages of software development, the major source of performance issues are unhandled errors and exceptions. To identify and correct them, use web server logs or tools like XDebug.
As more errors are eliminated and the application grows stable, reducing the page load time becomes the next focus. Now, the major source of performance issues lies in the core business logic and integration of various components like databases, cache, and third-party APIs. Benchmarking your applications and identifying the processing time taken by different components becomes pivotal.
As the application matures, performance can be further improved by identifying frequently used blocks of code, minimizing redundant calls, caching, and distributing workloads across multiple servers. At this stage, continuous monitoring of errors, logs, and key metrics like response time and throughput is necessary to maintain the high availability of your applications and meet your SLAs
Commonly known performance bottlenecks
As the language evolved over the years, many performance bottlenecks were identified and incorporated as part of the language itself. Here we list some of the frequently encountered performance issues in PHP code.
1. Loops:
Let's take a simple script that loops through an array of objects. We can achieve this via one of three possible loop constructs. Here we use the for and foreach loops to understand how small changes can affect the speed of execution.
For demonstration, we ran the snippet by initializing the array with 500 thousand objects and got the following results:
As we can see, eliminating repeated function calls improves the performance of the loop. Since every line of code will be evaluated in PHP, pre-calculating repeated values can boost performance. In most cases, foreach loops perform better for read-operations, and while/for loops perform better on modifying the list that is being iterated.
2. Cache usage:
Caching is a well-known technique to improve the performance of any web application and is one of the most commonly offered pieces of advice given by any PHP developer.
Since PHP scripts recompile every time they execute, caching systems like OpCache (OpCode caching) store the results of these compilations in RAM to avoid repeated compiling, saving valuable CPU cycles. A more refined caching systems like Memcached enables caching of database objects, reducing the number of times expensive calls are made.
3. String manipulations:
For simple string evaluations, avoid using Regex manipulations, as they're slower than standard string functions. Instead of relying on preg_replace, use str_replace. In cases where multiple replacements are used, strtr offers better performance than str_replace.
4. Database connection objects:
While some plugins like Mysql_mux allow connection pooling, PHP language doesn't support pooling database connections, making these expensive operations in PHP. Using a cache system to avoid repeated connections and closing connections properly will help improve the performance of your PHP applications.
5. Using built-in language constructs:
Using built-in PHP functions instead of writing code manually for trivial tasks will help you avoid well known performance issues. Use special-purpose PHP functions and syntaxes instead of generic functions for efficient processing, such as isset() or empty() functions instead of count() to check if an array is initialized, or '===' operator over '==' to check equality. While these changes seem small, they can boost application performance.
Measuring PHP application performance
Measuring performance is not a one-time task. Application performance should be tracked continuously, and one way to do this is performance benchmarking.
Performance benchmarking is the process of evaluating the application performance using key metrics over time and across release cycles. These metrics are then compared with the baseline metrics to determine the change in performance. With each iteration, improvements in the existing baseline metric become the new baseline for future benchmarking.
Since the production environment involves processing a lot more data than quality assurance (QA) or user acceptance testing (UAT) environments, continuous monitoring is the ideal solution to track performance.
Monitoring tools continuously capture the average response time, throughput, database query processing time, cache component time, and industry-standard metrics like Apdex, allowing you to track periodic variations in these metrics. These tools also allow you to compare the changes in performance before and after doing a major update, helping you understand the impact of your code changes.
For demonstrating how useful a monitoring tool can be, we added a sleep function to delay execution by ~100 ms in the snippets mentioned above. We marked the change in the Site24x7 APM Insight tool; by comparing the results, we can see the real-time change in average response time. With these reports, you can track even mild performance variations at the individual script level.
Monitoring tools also capture slow transactions and exceptions, saving you considerable time in debugging these issues. We executed the aforementioned script with our Site24x7 APM Insight tool and got the following results. You can clearly see this saved the burden of writing time-tracking snippets to identify the performance of the scripts.
To conclude, PHP's scripting runtime leaves a considerable responsibility on the developers to tweak the performance of their applications. Reusing existing functions, using pre-calculated results, managing database connections properly, and caching of frequently used objects is essential to improve performance at the code level.
Debugging tools and logs are useful at the development stages to track errors. Performance profiling and benchmarking is essential in identifying and tracking issues in the pre-production stages. A continuous monitoring tool is necessary for tracking performance changes in the production environment. A monitoring tool can also supplement other tools and can be used to understand performance at the development and UAT phases.
If you're a small business and struggling to cope during the COVID-19 pandemic, we have put together some relief initiatives to help you navigate this crisis.