Fast PHP is mostly about a few settings and a lot of measuring. The language itself has become much quicker over the PHP 8 releases, so the biggest wins today usually come from configuration, database queries and caching rather than from rewriting loops.
This guide goes through those in the order that tends to pay off, and starts with the one step people skip.
Run a supported version
Newer versions are faster and get security fixes. According to php.net, four branches are supported today:
| Version | Status on 30 Oct 2026 | Security fixes until |
|---|---|---|
| PHP 8.5 | Active support | 31 Dec 2029 |
| PHP 8.4 | Active support | 31 Dec 2028 |
| PHP 8.3 | Security fixes only | 31 Dec 2027 |
| PHP 8.2 | Security fixes only | 31 Dec 2026 |
For new work, use PHP 8.4 or 8.5. If you are still on 8.2, plan the move now: it stops receiving security fixes at the end of 2026. Anything older than 8.2 gets no fixes at all.
Measure before you change anything
Guessing where the time goes is usually wrong. A profiler shows you which functions and queries take the time on a real request.
- Xdebug's profiler writes a detailed file for each request, which you open in a viewer such as KCachegrind, QCacheGrind or your IDE. It slows PHP down a lot, so use it on a development machine and never leave Xdebug loaded in production.
- SPX is a free, open-source profiler with a small overhead and a built-in web page for the results.
- Blackfire is a commercial service that can profile production safely and compare runs.
Write down a baseline (response time for a few key pages) before each change, and check it after. Keep the changes that help.
OPcache: the biggest single setting
Without OPcache, PHP reads and compiles every file on every request. OPcache keeps the compiled code in shared memory. Since PHP 8.5 it is always built into PHP, but you still control it with the usual settings. These are sensible values for a production server:
; php.ini (production)
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
With validate_timestamps=0, PHP never checks files for changes, which saves work on every request. The catch: after each deploy you must reload PHP-FPM, or the old code keeps running. If you prefer automatic pick-up, leave it at 1 and set opcache.revalidate_freq to a few seconds.
Check that the cache is big enough with opcache_get_status(). If the memory is full or the number of cached files hits the limit, raise the matching setting.
JIT: useful for heavy computation
The JIT compiler turns hot code into machine code. It is off by default (opcache.jit=disable since PHP 8.4). It helps code that spends its time calculating: image processing, maths, long-running workers. A typical web request spends most of its time waiting for the database or the network, so the JIT changes little there. Turn it on, measure, and keep it only if the numbers improve:
opcache.jit=tracing
opcache.jit_buffer_size=64M
Preloading
Preloading loads a set of files into OPcache once, when PHP-FPM starts, so every request finds them ready. It suits large frameworks with many classes. The gain is usually modest, every code change needs a PHP-FPM restart, and it is not available on Windows. Read the preloading section of the manual, then measure.
opcache.preload=/var/www/app/preload.php
opcache.preload_user=www-data
Composer autoloading
On production, install without development packages and build an optimised class map, so PHP finds classes without searching the disk:
composer install --no-dev --optimize-autoloader
Database queries
On most PHP sites the slowest part is the database. The usual problems are easy to spot once you look:
- Too many queries. A page that runs one query per item in a list (the "N+1" pattern) should load the items in one query instead.
- Missing indexes. Run
EXPLAINon slow queries. A full table scan on a large table usually means an index is missing. - Too much data. Select only the columns you need and paginate long lists.
- Unknown slow queries. Turn on the database's slow query log and review it every week.
EXPLAIN SELECT id, total
FROM orders
WHERE customer_id = 42
ORDER BY created_at DESC
LIMIT 20;
Caching
The fastest work is work you do not repeat. Cache in layers:
- In memory on one server: APCu for small values that are expensive to compute.
- Shared across servers: Redis or Memcached for sessions, query results and rendered fragments.
- In front of PHP: HTTP caching headers, or a page cache, for pages that are the same for every visitor.
Decide how each cached item is cleared when the data changes. A cache that shows stale prices is worse than a slow page.
PHP-FPM settings
PHP-FPM runs a pool of worker processes. If all workers are busy, new requests wait in a queue, which looks like a slow site even when the code is fast. Size the pool by memory: divide the memory you can give PHP by the average memory one worker uses, and set pm.max_children to that number or a little less.
; /etc/php/8.4/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 8
pm.max_requests = 1000
request_slowlog_timeout = 3s
slowlog = /var/log/php-fpm/www-slow.log
pm.max_requests restarts each worker after a number of requests, which contains slow memory leaks. The slow log records a stack trace for any request that runs longer than the timeout, which points you straight at the problem.
Common questions
- Will the JIT make WordPress or Laravel faster?
- Usually only a little, because those requests mostly wait on the database. Measure your own pages; some code paths gain more than others.
- Is PHP 8.2 still safe to run?
- It gets security fixes until 31 December 2026. After that it gets none, so upgrade before then.
- Should I set pm to static?
- On a dedicated server with steady traffic, static avoids the cost of starting workers. On a shared or quiet server, dynamic or ondemand saves memory.
- Why did my deploy not change anything?
- If validate_timestamps is 0, OPcache still serves the old code. Reload PHP-FPM after each deploy.
If you tune PHP for a living, Getting paid on Internetivo explains how professionals find paid tasks.