Skip to content

PHP Tutorial PHP Performance and Best Practices

Measuring Performance

Lesson 338 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

The first rule of performance: measure, do not guess. Programmers are often wrong about what is slow. Time spent speeding up code that was not the problem is wasted, and it can make the code harder to read.

Time a piece of code

index.php
PHP
<?php
function timeIt(callable $fn, int $times = 1): float
{
    $start = hrtime(true);   // nanoseconds, monotonic

    for ($i = 0; $i < $times; $i++) {
        $fn();
    }

    return (hrtime(true) - $start) / 1_000_000;   // milliseconds
}

$ms = timeIt(fn() => array_sum(range(1, 100000)), 20);

echo is_float($ms) && $ms >= 0 ? "measured something" : "bad";
Output
OUTPUT
measured something

hrtime(true) is better than microtime(true) for measuring, because it does not jump when the system clock changes. Print $ms yourself to see the real number on your machine. It will differ on every computer and every run.

Memory

index.php
PHP
<?php
$before = memory_get_usage();

$data = range(1, 50000);

$after = memory_get_usage();

echo $after > $before ? "the array used memory\n" : "?\n";
echo memory_get_peak_usage() >= $after ? "peak is at least the current use" : "?";
Output
OUTPUT
the array used memory
peak is at least the current use

memory_get_peak_usage() gives the highest amount used so far, the number you compare with memory_limit.

Compare two approaches fairly

index.php
PHP
<?php
$data = range(1, 20000);

$a = hrtime(true);
$viaLoop = 0;
foreach ($data as $n) {
    $viaLoop += $n;
}
$loopTime = hrtime(true) - $a;

$b = hrtime(true);
$viaBuiltin = array_sum($data);
$builtinTime = hrtime(true) - $b;

echo $viaLoop === $viaBuiltin ? "same result\n" : "different!\n";
echo "Both timed: " . (($loopTime > 0 && $builtinTime > 0) ? "yes" : "no");
Output
OUTPUT
same result
Both timed: yes

Always check that two versions give the same result, then compare times. Repeat the test several times, because the first run includes warm-up effects.

Log slow requests

In production, you cannot watch every page. Record the slow ones.

index.php
PHP
<?php
$start = hrtime(true);

register_shutdown_function(function () use ($start): void {
    $ms = (hrtime(true) - $start) / 1_000_000;

    if ($ms > 500) {
        error_log(sprintf("Slow request: %s took %.0f ms, %.1f MB", $_SERVER["REQUEST_URI"] ?? "cli", $ms, memory_get_peak_usage() / 1048576));
    }
});

Profilers

A profiler shows where time and memory go, function by function.

ToolNotes
Xdebug profilerWrites files you open in a viewer (QCachegrind, Webgrind)
BlackfireA hosted profiler with comparisons
XHProf / TidewaysLight profilers for production sampling
Laravel Telescope, Symfony Profiler, Query Monitor (WordPress)Show queries and timings in the browser

Open the report and look at the top entries. Usually a few calls (database queries, HTTP requests, big loops) account for most of the time.

What usually makes PHP pages slow

  1. Database queries: too many, slow, or unindexed (see Query Optimization).
  2. Remote calls: APIs without timeouts or caching.
  3. Missing caches (OPcache, data caches).
  4. Large loops over large data (see Efficient Loops).
  5. Too much memory: loading everything at once.
  6. Heavy front-end: huge images, unminified JavaScript. This is not PHP, but it is what the visitor feels.

PHP itself is rarely the bottleneck. A page that takes two seconds is almost always waiting for something.

The optimisation process

  1. Decide on a goal (“the product page loads in under 300 ms”).
  2. Measure the current state.
  3. Find the biggest cost with a profiler.
  4. Change one thing.
  5. Measure again. Keep it only if it helped.
dangerous
Do not micro-optimise
Whether to use single or double quotes, or ++$i or $i++, makes no measurable difference. Spend your effort on queries, caching and design, and keep the code readable.