Unlock PHP Performance: Master the Essential Basics for a Smooth User Experience

Hire a PHP developer for your project — click here.

by admin
php_performance_basics

Php performance basics: the quiet work that makes everything feel fast

There’s a particular kind of silence you only hear when a PHP app is “just fast enough.”

No one pings you on Slack.
No client writes an angry email.
The error logs are boring.

Users click, pages appear, and the app simply feels… normal.

That silence is never an accident.

If you’ve ever sat at your desk late at night, watching top or htop on a remote server, refreshing a slow page again and again, you know this: PHP performance isn’t about clever tricks. It’s about a series of basic, almost boring decisions, made carefully and consistently.

This is an article about those basics.

Not micro-optimizing for loops. Not exotic extensions you’ll never use in production. Just the foundation that every serious PHP developer should internalize — especially if you’re building something people actually depend on.

Friends, colleagues, fellow developers: let’s talk about making PHP quietly fast.

Why performance basics matter more than clever hacks

Most performance talks start with flame graphs and end with obscure tweaks.

Real life is more mundane.

  • A Laravel app that feels fine with 10 users, but collapses under 500.
  • A WordPress-based shop that works during the day, but timeouts appear every evening when traffic spikes.
  • A home‑grown legacy system where no one dares touch the config, so each request drags its feet for no good reason.

If you work in the PHP ecosystem — as a freelancer, an in‑house dev, or someone hiring through Find PHP — you will run into this. Sooner or later, an app will be “mysteriously slow,” and everyone will look at you.

Here’s the part people don’t say out loud:

Performance is anxiety management.

When an app is slow, humans feel it before they understand it. Support teams become tense. Product folks become impatient. Developers start guessing.

Basics cut through that. Basics give you a checklist, a map, a way to talk about performance that isn’t just “make it faster somehow.”

So let’s build that map.

Start with measuring, not guessing

Have you ever stared at a slow page and thought: “It’s probably the database”? Me too. Sometimes it is. Sometimes it’s Nginx, DNS, or a rogue HTTP request to an external API.

Two kinds of measurement

There are two ways to measure PHP performance:

  • Black-box measurements – from the outside:

    • Page load time in the browser
    • Time To First Byte (TTFB)
    • API response latency
    • Load tests with tools like ab, wrk, or k6
  • White-box measurements – from the inside:

    • Profilers (Xdebug, XHProf, Tideways, Blackfire)
    • Logs and metrics from PHP-FPM, the web server, the database
    • Simple timing logs (microtime(true) around critical code)

Both are necessary.

From the outside, you learn how bad it feels for a user.
From the inside, you learn why.

A simple personal rule

Before you “optimize” anything in a PHP app, answer these three questions:

  1. Which endpoint is slow? (exact URL or route, not “the site”)
  2. Which part of the request is slow? (DNS, TLS, PHP, DB, external API, frontend)
  3. Can I prove it with numbers?

If you can’t, you’re guessing.

Even a crude log line like this can help:

$start = microtime(true);

// ... do stuff ...

$duration = microtime(true) - $start;
error_log(sprintf('[PERF] /checkout took %.3f seconds', $duration));

Is this pretty? Not really. Does it beat guessing? Every single time.

Use a modern PHP version (it isn’t optional anymore)

Updating PHP is the most boring performance advice, and also the most effective.

PHP 7 was a massive leap. PHP 8 and 8.1 continued that trend. PHP 8.2 and 8.3 refine it further. The difference between an old PHP 7.x and a well‑tuned PHP 8.2/8.3 stack can be:

  • 2–3x faster request handling in real‑world apps
  • Lower memory usage per process
  • New features, better typing, fewer weird edge cases

You will find all sorts of advanced optimization tips online, but if you’re still on an old version, you’re effectively driving a sports car with the handbrake on.

If you’re hiring PHP developers through something like Find PHP, you can tell a lot about their experience from how confidently they talk about PHP version support, deprecations, and migration strategies. People who live in older versions often underestimate how much performance they’re leaving on the table.

So: step one of PHP performance basics in 2025 and beyond is simple.

Run something reasonably recent. Learn what changed. Use it.

You don’t have to be on the absolute bleeding edge, but running EOL versions in production is not a “cost saving.” It’s performance and security debt with interest.

Opcache: the single checkbox that changes everything

Here’s the thing about PHP: it wasn’t designed for long-living processes originally. It reads your .php file, parses it, compiles it to bytecode, executes it, and then throws everything away.

Doing that on every single request is… wasteful.

That’s why OPcache exists.

What OPcache actually does

OPcache stores the compiled bytecode of your PHP scripts in memory. On the next request, PHP can skip parsing and compilation and just execute the cached bytecode.

The result:

  • Less CPU per request
  • Faster responses, especially under load
  • More stable performance as traffic grows

In many articles you’ll see claims like “2–3x faster by enabling OPcache,” and honestly, they’re not exaggerating. For some apps, that’s exactly what happens.

Minimum viable OPcache config

This is not a full tuning guide. It’s the basic idea:

opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=2

Is this perfect for your app? Maybe not. But it’s infinitely better than leaving OPcache disabled.

If you’ve ever been on call during a traffic spike, you know this feeling: CPU hits 100%, requests crawl, and you’re praying it’s not a deployment bug. Enabling OPcache is like finally putting power steering into your old car. It’s still the same car, but now it handles weight much better.

Think in round trips: the true cost of “just one more query”

When people say, “My PHP app is slow,” they usually mean, “My app is slow because of the database.”

PHP is fast at stringing bytes together and sending them over the network. It is terrible at waiting. Every network call — to MySQL, Redis, another HTTP service — is an invitation to latency.

That is why the real basics of PHP performance are largely:

  • Doing fewer queries
  • Doing lighter queries
  • Doing them in a smarter way

The N+1 query: the classic sin

Imagine a snippet:

$posts = Post::latest()->limit(20)->get();

foreach ($posts as $post) {
    echo $post->author->name;
}

If your ORM isn’t set up to eager‑load author, you just did:

  • 1 query for posts
  • 20 queries for authors

On your laptop, it’s fine. On a server across the network — or with thousands of users doing the same thing — it’s a disaster.

The fix is not rocket science:

$posts = Post::with('author')->latest()->limit(20)->get();

Suddenly:

  • Total queries: 2
  • Latency: dramatically better
  • Database: calmer

If you do only one “performance exercise” this week, do this: take a real page from your app, enable query logging in your framework, and count how many queries run. The number will probably surprise you.

Indexes: the difference between “instant” and “never finishes”

A PHP script asking for a user by email:

SELECT * FROM users WHERE email = 'user@example.com';

With a proper index on email, this comes back quickly. Without one, MySQL scans the whole table.

At 1,000 rows, you won’t notice.
At 10,000 rows, you’ll occasionally notice.
At 10,000,000 rows, you’ll be the person staring at a slow query log at midnight.

The PHP code didn’t change. The performance did.

The basics here:

  • Understand what columns you filter and join on.
  • Add indexes accordingly (with care — too many indexes also hurt).
  • Use EXPLAIN to see how the database actually runs your query.
See also
Build Scalable and Efficient PHP Projects with This Simple Lightweight Structure Guide

No amount of clever PHP will fix a query that is fundamentally unindexed.

Caching as a habit, not a patch

Caching is where many developers jump prematurely. They slap Redis or Memcached on top of a messy system and hope it will “absorb” the slowness.

Caching doesn’t work that way.

Caching is a habit: a way of thinking about what truly needs to be dynamic and what doesn’t.

Three simple layers of caching

For PHP apps, caching usually appears in three layers:

  • Opcode cache – OPcache (we already covered this).
  • Application/cache layer – Redis, Memcached, or file cache for:
    • Expensive queries
    • Computed views
    • Rate limiting, sessions (if you must use sessions)
  • HTTP-level caching – browser and CDN:
    • Cache-Control, ETag, Last-Modified
    • CDN edge caching for static assets, sometimes full HTML

Many teams overcomplicate the second layer and ignore the third. That’s backwards. Sending a Cache-Control: public, max-age=600 with a static asset will outperform any clever PHP micro-optimization.

A modest caching pattern

Imagine a dashboard where you need to crunch a bunch of numbers.

Instead of doing the heavy computation on each request:

$key = 'dashboard_stats_user_' . $userId;

$stats = $cache->get($key);

if ($stats === null) {
    $stats = $this->computeStatsForUser($userId);
    $cache->set($key, $stats, 300); // 5 minutes
}

return $stats;

Is this elegant? Not particularly.
Does it often turn 2-second pages into 200ms pages? Absolutely.

The basic question to ask yourself is:

Does this information really need to be fresh on every single request?

Most of the time, the honest answer is no.

Php-fpm and friends: don’t ignore the engine room

At some point in your career, you discover that performance problems have nothing to do with your PHP code. The code is fine. The bottleneck is PHP-FPM configuration, or max_children, or the web server limits.

This is the part many pure “application developers” avoid, but it’s part of the basics now.

The mental model

A very simplified picture:

  • The web server (Nginx, Apache, Caddy) receives HTTP requests.
  • It forwards PHP requests to PHP-FPM (FastCGI).
  • PHP-FPM manages a pool of worker processes.
  • Each worker handles one request at a time.

So if:

  • You have pm.max_children = 10,
  • And each request takes 1 second,
  • And you suddenly get 100 concurrent requests,

90 of them will wait. Some will time out. Everything feels “slow.”

Simple levers to know about

You don’t need to be a sysadmin, but you should understand:

  • pm.max_children – how many PHP processes can run at once
  • pm.max_requests – after how many requests a worker is recycled
  • Memory per PHP process – too many children can exhaust RAM
  • Web server timeouts – a slow backend will surface as 502/504

Watching logs in real time during load is actually quite educational. The first time you see PHP-FPM logs screaming “server reached max_children,” something clicks. The app wasn’t “mysteriously slow.” It was waiting in line.

Code that respects the CPU

Let’s talk about the part we, as developers, have direct control over: the code.

Performance tuning isn’t writing “ugly” code. It’s writing code that respects both the CPU and the next person who has to maintain it — which might be you, three months from now, with half the context and twice the pressure.

Avoid work you don’t need to do

PHP is fast at many things. It is horrible at work you didn’t need to do.

A few recurring patterns:

  • Repeated calculations inside loops:
    • Move invariant work outside the loop.
  • Unnecessary type juggling or JSON encoding/decoding:
    • Don’t serialize/deserialize data three times in the same request.
  • Heavy operations done synchronously:
    • Sending bulk emails, generating PDFs, large imports — offload to queues.

A tiny, concrete example:

// Bad: calculating strlen on each iteration
for ($i = 0; $i < strlen($str); $i++) {
    // ...
}

// Better:
$len = strlen($str);
for ($i = 0; $i < $len; $i++) {
    // ...
}

On its own, this change doesn’t save the world. But the mindset behind it scales. You start seeing unnecessary work everywhere.

Use native functions and data structures

PHP has a ridiculous number of built-in functions. Many of them are written in C and heavily optimized. Trying to “beat” them with pure PHP code usually ends in tears.

Examples:

  • in_array() with strict mode vs custom loops
  • array_map, array_filter, array_column
  • implode / explode instead of manual concatenation
  • json_encode/json_decode with options instead of weird hacks

A classic pattern:

// Don't reinvent this:
$result = [];
foreach ($users as $user) {
    $result[] = $user['email'];
}

// When you could do:
$result = array_column($users, 'email');

Is array_column drastically faster in all cases? Not always. But it’s often faster and more readable.

The real performance win is that the code is now clearer; future developers won’t accidentally make it worse while trying to “fix” your custom loop.

Asynchronous and deferred work: queues are not just for “big” systems

There’s a moment you remember clearly the first time you use a queue in a real project.

You move some heavy operation — like sending an email with attachments — out of the HTTP request and into a background worker. You reload the page and suddenly it’s fast. Nothing else changed.

PHP doesn’t have native async in the same way Node.js does, but you can still think asynchronously:

  • Use job queues (Beanstalkd, Redis-based queues, RabbitMQ, SQS).
  • Use cron to pre-generate expensive reports.
  • Use webhook callbacks instead of blocking on external APIs.

If a user does something that triggers heavy work, that heavy work doesn’t have to block their request. This is one of the most humane performance improvements you can make. It’s not just about CPU, it’s about perceived responsiveness.

And that’s ultimately what users care about.

Performance in teams: how to talk about it like adults

On platforms like Find PHP, you’ll often see “performance optimization” listed as a skill. That’s nice, but performance in real teams is more than a bullet point on a CV.

It’s conversations like:

  • “Is it okay if this page takes up to 2 seconds, as long as it’s stable?”
  • “Can we cache this for 5 minutes without breaking business rules?”
  • “Is it worth adding complexity here for a 10% speed improvement?”

The basics are:

  • Define acceptable performance.
    • For example: 95% of requests under 500ms for key endpoints.
  • Decide what you will measure.
    • TTFB, error rate, DB slow queries, queue length.
  • Share the mental models with non‑developers.
    • Explain why adding a “simple report” could mean serious DB load.
    • Explain why “flush all caches” is not a neutral button.

Performance stops being magic when more people understand its trade‑offs. That makes your job easier. It also makes your work more visible and respected.

The emotional side: late nights with logs and quiet wins

Every developer who stays in PHP long enough has a story like this:

  • A production incident.
  • Timeouts everywhere.
  • People nervous in a group chat.
  • You, staring at logs, CPU graphs, DB metrics, eyes dry from too much coffee.

You try a thing, it doesn’t help. You try another. You curse an ORM, a config file, maybe your past self.

Then, eventually, you find it.

  • A missing index.
  • OPcache was off.
  • PHP-FPM was hitting max children.
  • Some innocent-looking loop doing 5000 queries.

You patch it.
Deploy.
Watch the graphs fall into normal ranges.

And then… nothing.

No one applauds. No one writes a long thank‑you. The app simply feels fine again. Support tickets slow down. People go back to their roadmap.

This is the quiet life of performance work: when it’s done well, it becomes invisible.

But you feel it.

You remember the before and after. You remember the moment the latency graph dropped. You remember the first time you reloaded a formerly slow page and it came back instantly, and you almost laughed from relief.

Bringing it all together

Let’s recap the truly basic, non‑exotic foundation of PHP performance:

  • Measure first, guess later.
  • Run a modern PHP version.
  • Enable and tune OPcache.
  • Reduce database queries, especially N+1 patterns.
  • Use proper indexing and inspect queries with EXPLAIN.
  • Cache deliberately: opcode, application data, HTTP responses.
  • Understand the basics of PHP-FPM and web server limits.
  • Write code that avoids unnecessary work and leans on native functions.
  • Push heavy tasks into queues and background workers.
  • Talk about performance with your team, not just your terminal.

None of this is glamorous. You won’t post most of it on social media. But these are the habits that separate “it works on my machine” from “it runs smoothly in production for years.”

Somewhere right now, a PHP developer is looking at a slow page and feeling that familiar mix of frustration and responsibility. Maybe that’s you. Maybe it will be you next week.

When that moment comes, remember: you don’t need magic.

You need basics, patience, a few solid tools — and the quiet confidence that comes from knowing this is just another problem you can untangle, one careful step at a time.
перейти в рейтинг

Related offers