PHP at EGPHP
Everything we build begins with PHP.
Our team has written and run PHP for twenty-five years, since PHP 4. The servers, the control panel and the sites we look after all start here.
Twenty-five years, release by release
We did not read about these versions. We upgraded real sites through each of them, and every row below is a change we had to deal with on a live server.
-
PHP 4 2000
Sessions and output buffering, built in
The Zend Engine arrived, and sessions and output buffering became part of the language instead of add-ons. A generation of early dynamic sites was written against it.
Zend Enginesession_start()ob_start()
What it meant for usWhere our team started: hand-written sites on shared servers, with register_globals still switched on.
-
PHP 5.0 2004
A real object model
Zend Engine 2 brought classes with visibility, interfaces and exceptions, objects passed by handle instead of copied, and the MySQLi and SimpleXML extensions.
privateinterfacetry / catchmysqli
What it meant for usCode could be organised into classes a team shares, and the database got a modern driver.
-
PHP 5.3 2009
Namespaces and closures
Namespaces, anonymous functions and late static binding: the ground that Composer and the shared package ecosystem were later built on.
namespacefunction () use ()static::
What it meant for usLibraries from different authors could finally live in one project without their names colliding.
-
PHP 5.4 2012
Traits, short arrays and a clean-up Broke old code
Traits, the short [] array syntax and a built-in development server, while register_globals, magic quotes and safe mode were removed for good.
trait[ ]php -S
What it meant for usOld sites that relied on register_globals stopped working, and upgrading them meant fixing them first.
-
PHP 5.5 2013
OPcache in the box
OPcache shipped with PHP itself and kept compiled scripts in memory, alongside generators and password_hash().
opcacheyieldpassword_hash()
What it meant for usCompiled code kept in memory instead of re-read on every request. It is still the first setting we check on any PHP server.
-
PHP 6 never released
The version that never shipped
PHP 6 was planned around native Unicode strings and abandoned. The next release was numbered 7 so it would not be confused with the books and plans written for 6.
-
PHP 7.0 2015
The speed jump Broke old code
A rebuilt engine, which the PHP project described as up to twice as fast as 5.6 while using less memory, plus scalar and return type declarations, ?? and <=>.
int $id: string??<=>
What it meant for usThe old mysql_* functions were removed, a frequent reason an old site broke on this upgrade.
-
PHP 7.4 2019
Typed properties and preloading
Typed properties, arrow functions, the ??= operator, OPcache preloading and FFI.
public int $idfn ($x) =>??=
What it meant for usThe last 7.x release, and the one many older applications stayed on longest, which is why we still move sites off it.
-
PHP 8.0 2020
JIT, attributes and named arguments Broke old code
A JIT compiler, attributes, named arguments, union types, match, the nullsafe ?-> operator and constructor property promotion.
#[Attribute]match?->JIT
What it meant for usMany warnings became errors and comparisons between strings and numbers changed, so code that ran quietly on 7.4 could stop on 8.0.
-
PHP 8.1 2021
Enums, readonly and fibers
Native enums, readonly properties, fibers, the never return type and first-class callable syntax.
enumreadonlyFibernever
What it meant for usFibers opened the way for asynchronous PHP libraries without changing how an ordinary request runs.
-
PHP 8.2 2022
Readonly classes, and a warning for old code
Readonly classes, DNF types, true, false and null as standalone types, and a new Random extension.
readonly class(A&B)|nullRandom\Randomizer
What it meant for usDynamic properties were deprecated, and older plugins filled the logs with notices until they were updated.
-
PHP 8.3 2023
Typed constants and #[\Override]
Typed class constants, the #[\Override] attribute, json_validate() and dynamic class constant fetch.
const string#[\Override]json_validate()
What it meant for usA quieter release, which makes it an easy step for sites already on 8.2.
-
PHP 8.4 2024
Property hooks
Property hooks, asymmetric visibility, lazy objects, an HTML5-aware DOM parser, and new MyClass()->method() without the extra brackets.
get { }public private(set)Dom\HTMLDocument
What it meant for usGetters and setters that used to need a method each now belong to the property itself, so there is less code to maintain.
-
PHP 8.5 2025
The pipe operator Current
The |> pipe operator, a built-in URI extension, clone with, the #[\NoDiscard] attribute, array_first() and array_last(), and a backtrace on fatal errors.
|>Uri\Rfc3986\Uriclone($o, [ ])
What it meant for usThe current release line, and the one we start new sites on when their code supports it.
Years are those of each first release in the PHP project's own release history.
Follow one request down the stack
A page on a PHP site passes through five layers on its way in, and back up through the same five on its way out. We look after every one of them, and each has its own page.
-
The visitor
A browser asks for a page over HTTPS. The certificate, the firewall and the rules in front of the server decide whether the request is let in at all.
-
The web server
Nginx or LiteSpeed takes the connection, serves images and files itself, and hands only the PHP work to the pool behind it.
-
The PHP runtime
PHP-FPM pools, one per site, each on the PHP version its code needs, with OPcache warm and workers sized for the traffic.
-
Your code
A framework or a ready-made platform turns the request into a page: your own Laravel application, or WordPress, Magento, Moodle and the rest.
-
The data
MySQL or MariaDB keeps the records, and Redis keeps in memory what is asked for again and again.
The server itself
Our own servers, run by the same team, with our own control panel on top.
Moving to a newer PHP without a bad morning
Each site gets its own pool, so one server can run several PHP versions side by side and every site moves when its code is ready, not when the server is.
We list what each site runs
Its PHP version, its extensions, and the plugins or packages that hold it back.
A copy tries the new version
The site is copied and run on the next PHP version, and its error log is read line by line.
We fix what breaks
Removed functions, deprecated calls and plugins with no update are fixed or replaced.
One site at a time
Each site switches to its new pool on its own, and can be switched back at once if anything was missed.
| Site | PHP | Pool | State |
|---|---|---|---|
| shop.example.com | 8.4 | fpm-shop | live |
| blog.example.com | 8.3 | fpm-blog | live |
| crm.example.com | 7.4 → 8.3 | fpm-crm | on a copy |
| learn.example.com | 8.3 | fpm-learn | live |

Bring us your PHP
An old site that needs a newer PHP, a platform to install, or a server to run it all on. Every job is quoted after a short conversation.