5.2 · Performance: caching, OPcache, Redis

Level 5 · Pro level & deployment

5.2Performance: caching, OPcache, Redis

Goal: know the PHP performance levers (OPcache, cache/Redis, database optimisation, profiling) and know how to apply them at the right time (with measurements to back you, no premature optimisation).
Estimated time: 11 min · self-paced reading · If you only have 5 min: read “The essentials in 30s” + the diagram.

The essentials in 30 seconds

  • OPcache: the compiled bytecode is cached — compiled once instead of on each request, a major almost-free gain.
  • Application cache: storing costly results (Redis) so they are not redone — often the most impactful lever.
  • Measure first: profile to find the real bottleneck (often the database) — never premature optimisation.

Running case — Riad speeds up his shop in Constantine

Riad's restructured shop in Constantine crawls at peak hours: the home page takes time to respond. Rather than rewriting everything, he measures: OPcache is not enabled in production, and the same catalogue queries keep hitting the database. He enables OPcache and caches the catalogue. Sequel of case 5.1 — Riad optimises what he measured, not at random.

Sequel of case 5.1 — Riad applies the golden rule: measure first, optimise second.

1. OPcache: the almost-free gain

PHP is interpreted: on each request, the server compiles the code (into “bytecode”) before running it. Redoing this compilation on each request, while the code does not change, is waste. OPcache is an extension (generally available) that caches the compiled bytecode: compile once, then reuse — a major, almost-free performance gain. Riad checks it is enabled and well configured in production (in development, it is sometimes disabled to see changes at once). Modern PHP versions also bring large intrinsic gains.

Reflex: a PHP application in production without OPcache is much slower for no reason — it is the basic optimisation, before any other.

2. Application cache and Redis

The most impactful lever on real applications is caching: storing costly, rarely-changing results (frequent queries, heavy computations, pages or fragments, external API data) so they are not redone on each request. For a fast, shared cache, Redis (or Memcached) is often used — an in-memory store, hence very fast, also used for sessions or queues. Frameworks (Laravel, Symfony) include easy-to-use cache systems, with several drivers. Riad caches the catalogue with a short lifetime: repeated queries no longer touch the database.

Rule of choice: cache what is costly to produce and tolerates being slightly stale — with a clear refresh strategy.

3. Database, profiling and the right approach

The database is often the real bottleneck: slow or unindexed queries, and the famous N+1 problem (common with ORMs: one query per item in a list instead of one — fixed by grouped loading of relations, “eager loading”). Indexing the searched columns and optimising queries often has the biggest impact. And the method overlooking it all: profiling — measuring before optimising to identify the real bottlenecks rather than optimising blind. Riad profiles before touching the code: the slowness came from the database, not his loops.

Transversal principle: do not optimise prematurely. Correct, clear code first, measure when a problem occurs, then targeted optimisation. Optimising too early wastes time and needlessly complicates.

Common misinterpretation: “My app is slow, I optimise my PHP loops”. No. Without measurement, you almost always optimise the wrong place: first check OPcache in production (the free gain), then the database (unindexed query, N+1) and the missing cache — not your loops. Intuition misleads, measurement decides: profile, fix the real bottleneck, re-measure.
Optimising at the right time Measure before optimising OPcache Compiledbytecode only onceCache (Redis) Costly resultsserved without recomputationDatabase & profiling Indexes, N+1,measuring the real bottleneck
Measure before optimising
Text version of the diagram (SEO / screen readers / translation): 1) OPcache: Riad checks that his shop's bytecode in Constantine is compiled only once in production. 2) Cache: he caches the catalogue (Redis) with a short lifetime — repeated queries no longer touch the database. 3) Database and profiling: he indexes the searched columns, fixes N+1 with grouped loading, and re-measures. Lesson: the free gain first, then the measured real bottleneck.

🔎 Concrete example — Riad caches the catalogue

Check OPcache, then cache a costly result.

query('SELECT id, nom, prix FROM produits')->fetchAll(PDO::FETCH_ASSOC);
    file_put_contents($fichier, json_encode($lignes));
    return $lignes;
}

Reading: check the free gain (OPcache), then avoid redoing the costly (cache with a lifetime).

Lesson: in production, this cache would live in Redis — shared between all processes.

Section vocabulary

OPcache
Extension that caches the compiled PHP bytecode, compiled only once.

Simple example: Riad enables it in production: no more recompiling on each request.

What it is not: an HTML page cache.

Reflex: is OPcache enabled on my production?

Caching
Storing costly results so they are not recomputed each time.

Simple example: Riad's catalogue served from the cache, no longer from the database.

What it is not: adding servers before caching.

Reflex: which queries keep coming back identically?

Redis
Fast in-memory store, often used as a shared cache.

Simple example: Riad places the catalogue there with a short lifetime.

What it is not: the main database itself.

Reflex: does this result tolerate being slightly stale?

N+1 problem
One query per item in a list instead of a single grouped query.

Simple example: Riad loads the reviews of 50 products at once, not in 50 queries.

What it is not: a lack of memory on the server.

Reflex: how many queries go out to display this list?

Profiling
Measuring to identify the real bottlenecks before optimising.

Simple example: Riad discovers the slowness comes from an unindexed query.

What it is not: optimising his loops by intuition.

Reflex: did I measure before touching the code?

In practice — Optimising a PHP application

  1. Check that OPcache is enabled and well configured (especially in production) — a major almost-free performance gain (cached compiled bytecode).
  2. Cache a costly result (a frequent query) — in memory or with Redis — and measure the gain; use a framework's cache system.
  3. Optimise the database: index the searched columns, spot and fix the N+1 problem (grouped loading of relations) — often the biggest impact.
  4. PROFILE to identify the real bottlenecks BEFORE optimising (measure before optimising); do not optimise prematurely (correct code first).
You know the PHP performance levers (OPcache, cache/Redis, database optimisation, profiling) and know how to apply them at the right time (with measurements to back you, no premature optimisation).

Ready-to-say script — justifying an optimisation

“In Constantine, our shop slows down at peak hours. I measured: OPcache is not enabled in production and the catalogue queries saturate the database. I suggest two targeted moves: enable OPcache and cache the catalogue with a short lifetime. We re-measure after, and we only touch the infrastructure if measurement justifies it.”

Say to the manager to get a measured optimisation approved rather than a blind rewrite.

Copy-paste template — perf diagnosis sheet

PERF — DIAGNOSIS
SYMPTOM: _______________ (when? ___) 
OPCACHE: enabled in production? ___ 
MEASUREMENT: response time ___ · slowest query ___ 
SUSPECTED BOTTLENECK: missing cache / database (index, N+1) / code: ___ 
TARGETED ACTION: OPcache / Redis cache / index / eager loading: ___ 
RE-MEASUREMENT: before ___ → after ___ · GAIN: ___

Solo / small budget

Riad alone: OPcache + file cache on the costly pages is enough — Redis will come when traffic justifies it.

Small business / small team

Index the slow queries first: often the fastest gain, with no new infrastructure.

SME in Constantine

Riad plans measurements at peak hours in Constantine, with a re-measurement protocol after each change.

Starting team

Pair: one profiles while the other prepares the cache; joint review of measurements before any optimisation.

✓ Best practices

  • Check OPcache in production before any other optimisation (the free gain).
  • Cache costly results; index and fix N+1.
  • Measure (profile) before optimising, and target the real bottlenecks.

✗ Common pitfalls

  • Optimising your loops by intuition without measuring (the bottleneck is elsewhere).
  • Forgetting OPcache in production (slowness for no reason).
  • Caching with no lifetime or refresh strategy (stale data).

Key takeaways

  • OPCACHE: caches the compiled PHP BYTECODE (compilation only once instead of on each request) — a MAJOR almost-free gain. To enable/configure, especially in production.
  • CACHING (often the most impactful): storing COSTLY results (frequent queries, computations, pages) so they are not redone; REDIS (fast in-memory store). Frameworks include caching.
  • DATABASE optimisation (often the real bottleneck): index, optimise queries, fix N+1 (grouped loading). PROFILE (measure) BEFORE optimising (golden rule).
  • Do NOT optimise PREMATURELY: correct, clear code first, MEASURE when a problem occurs, then TARGETED optimisation. Optimising too early = wasted time + needless complexity.

48h challenge — apply tomorrow

Fill in the diagnosis sheet for 1 real slowness of your app: OPcache checked, measurement, suspected bottleneck — without touching the code yet.

Section exit checklist
  • I can explain OPcache vs application cache in one sentence.
  • My diagnosis sheet (measure before optimising) is filled in.
  • I know why the database is the first suspect.
Self-rating 1-5: did I measure before optimising?is OPcache enabled on my production?

Frequently asked questions

What are OPcache and caching, and how to improve the performance of a PHP application?

Two different, complementary mechanisms. OPcache fixes waste specific to PHP: recompiling code on each request. It caches the compiled bytecode — compile once, reuse — a major almost-free gain, to enable especially in production. The application cache fixes another waste: redoing costly operations (frequent queries, computations, pages) while the result changes little. The result is stored (often in Redis, in memory, very fast) with a lifetime. Added to this are database optimisation (indexes, fixing N+1 — often the real bottleneck) and profiling: measuring to optimise where it counts, never blind.

How to know when and what to optimise without falling into premature optimisation?

Golden rule: do not optimise before a real, measured problem. Premature optimisation wastes time, complicates code and misses the real bottleneck (intuition misleads). The approach: correct, clear code first, measure (profiling, query times) when a problem occurs, targeted optimisation where it counts (OPcache, cache, database), re-measure to confirm the gain. Most code does not need optimising: a small part concentrates most of the cost — measurement designates it.

Check your understanding

What is the first performance reflex on a PHP app in production?

Additional resources (optional, to go further)

Level 5 examFresh, harder questions to test what you've learned