0

What is PHP 8.4 and where it runs

Beginner5 min read·php-01-001

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:

  1. The web server (Nginx, Apache, Caddy) receives the HTTP request
  2. It hands off .php files to the PHP interpreter (via FastCGI, module, or CLI)
  3. PHP parses, compiles to opcodes, and executes your script
  4. The output (HTML, JSON, binary) is sent back as an HTTP response
  5. 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 visibilitypublic private(set) for read-only public + private mutation
  • array_find() / array_find_key() — native functional array search
  • HTML5 parser in Dom\HTMLDocument replacing 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:

StageWhat happens
LexingSource → tokens (T_ECHO, T_STRING, etc.)
ParsingTokens → Abstract Syntax Tree (AST)
CompilationAST → opcodes (bytecode)
ExecutionZend 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
<?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.