What is PHP 8.4 and where it runs
Concept
PHP 8.4 is the server-side scripting language that powers roughly 77% of the web — from WordPress to Wikipedia to Facebook's early days. Understanding where it runs and how it executes is the mental model you carry into every debugging session and performance investigation.
PHP executes on the server, not the browser. When a user requests a URL:
- The web server (Nginx, Apache, Caddy) receives the HTTP request
- It hands off
.phpfiles to the PHP interpreter (via FastCGI, module, or CLI) - PHP parses, compiles to opcodes, and executes your script
- The output (HTML, JSON, binary) is sent back as an HTTP response
- PHP's state is wiped — no memory of previous requests by default
This shared-nothing architecture is both PHP's superpower (horizontal scaling is trivial) and its biggest gotcha (no global state means every request starts fresh).
PHP 8.4 specifically adds
- Property hooks — get/set logic directly on class properties
- Asymmetric visibility —
public private(set)for read-only public + private mutation array_find()/array_find_key()— native functional array search- HTML5 parser in
Dom\HTMLDocumentreplacing the ancient libxml parser #[\Deprecated]attribute — first-class deprecation notices
The jump from PHP 5 to 7 was speed. PHP 7 to 8 was type safety. PHP 8.x is developer ergonomics — the language is becoming as expressive as it is fast.
The Zend Engine underneath
Your .php source goes through four stages every request:
| Stage | What happens |
|---|---|
| Lexing | Source → tokens (T_ECHO, T_STRING, etc.) |
| Parsing | Tokens → Abstract Syntax Tree (AST) |
| Compilation | AST → opcodes (bytecode) |
| Execution | Zend VM runs the opcodes |
OPcache short-circuits stages 1–3 by caching compiled opcodes in shared memory. This is why enabling OPcache in production gives you a 3–10× throughput boost with zero code changes.
Code Example
<?php
declare(strict_types=1);
// PHP 8.4: property hooks — computed properties without boilerplate
class Temperature {
public float $celsius {
get => $this->celsius;
set(float $value) {
if ($value < -273.15) {
throw new \ValueError("Temperature below absolute zero");
}
$this->celsius = $value;
}
}
// Asymmetric visibility: public read, private write
public private(set) int $readCount = 0;
public function read(): string {
$this->readCount++;
return "{$this->celsius}°C / {$this->toFahrenheit()}°F";
}
private function toFahrenheit(): float {
return $this->celsius * 9/5 + 32;
}
}
$temp = new Temperature();
$temp->celsius = 100.0; // setter runs, validates
echo $temp->read(); // "100°C / 212°F"
echo $temp->readCount; // 1 (public read works)
// $temp->readCount = 5; // Fatal: private(set) prevents external writes
// PHP 8.4: array_find() — returns first match or null
$temps = [
['city' => 'Bucharest', 'celsius' => 35],
['city' => 'Oslo', 'celsius' => 12],
['city' => 'Dubai', 'celsius' => 45],
];
$hot = array_find($temps, fn($t) => $t['celsius'] > 40);
// ['city' => 'Dubai', 'celsius' => 45]
$hotCity = array_find_key($temps, fn($t) => $t['celsius'] > 40);
// 2 (array index)Interview Q&A
Q: Where does PHP execute and why does that matter for state management?
PHP executes on the server, not the client. Each HTTP request spawns a fresh PHP process (or re-uses a worker with cleared state). This shared-nothing model means: no request can accidentally corrupt another's state, horizontal scaling is dead simple (just add servers), but it also means you must persist state externally (database, Redis, sessions) if you need it across requests. Understanding this prevents an entire class of "why didn't my variable update?" bugs.
Q: What is OPcache and when would you disable it?
OPcache stores the compiled bytecode (opcodes) of your PHP files in shared memory, bypassing the lex/parse/compile pipeline on subsequent requests. In production this is always on — it's free performance (3–10× throughput). You'd disable or reduce opcache.validate_timestamps only in development where you need file changes to take effect immediately without cache invalidation. Never set validate_timestamps=0 in dev.
Q: What's the practical difference between PHP-FPM and the CLI SAPI?
php-fpm is the FastCGI Process Manager — it keeps a pool of PHP workers alive, receives requests from Nginx/Apache over a Unix socket or TCP, and processes them without the startup overhead of forking a new process. The CLI SAPI is what you use for scripts, artisan commands, and queue workers — it starts, runs your script, exits. The key difference: FPM has request lifecycle hooks (RINIT/RSHUTDOWN), persistent opcode cache across requests, and configurable worker pools. CLI has none of those but has no timeout (unless you set max_execution_time), which is why it's used for long-running jobs.