Why PHP 8 Breaks Old Code
PHP 8.0 (released 2020) and PHP 8.1/8.2 made the language stricter. Functions that were "deprecated" in PHP 7.x (meaning: still works, but you'll get a warning) became fatal errors in PHP 8.
If your site broke after a server upgrade, one of these is almost certainly the cause.
The Most Common Breakages
1. mysql_* Functions (Removed in PHP 7, Fatal in PHP 8)
// BROKEN — removed completely
$conn = mysql_connect("localhost", "user", "pass");
$result = mysql_query("SELECT * FROM products");
// FIXED — use mysqli or PDO
$conn = new mysqli("localhost", "user", "pass", "dbname");
$result = $conn->query("SELECT * FROM products");
If you're still on mysql_*, your code is at least 10 years old. The rewrite is straightforward but tedious for large codebases.
2. ereg() and ereg_replace() (Removed in PHP 7)
// BROKEN
if (ereg("^[a-z]+$", $str)) { ... }
$clean = ereg_replace("[^a-z0-9]", "", $str);
// FIXED — use preg_ equivalents
if (preg_match("/^[a-z]+$/", $str)) { ... }
$clean = preg_replace("/[^a-z0-9]/", "", $str);
3. create_function() (Removed in PHP 8.0)
// BROKEN
$fn = create_function('$x', 'return $x * 2;');
// FIXED — use anonymous function
$fn = function($x) { return $x * 2; };
// or arrow function
$fn = fn($x) => $x * 2;
4. each() (Removed in PHP 8.0)
// BROKEN
while (list($key, $val) = each($array)) { ... }
// FIXED
foreach ($array as $key => $val) { ... }
5. $HTTP_*_VARS Globals (Long gone, but still in old code)
// BROKEN — these haven't existed since PHP 5.4
$id = $HTTP_GET_VARS['id'];
$name = $HTTP_POST_VARS['name'];
// FIXED
$id = $_GET['id'];
$name = $_POST['name'];
6. Passing null to Non-Nullable Parameters (PHP 8.1)
This is the sneaky one that breaks lots of modern-ish code:
// BROKEN in PHP 8.1 — strlen doesn't accept null
$len = strlen(null); // Fatal: strlen(): Argument #1 must be of type string, null given
// FIXED
$len = strlen($value ?? '');
// or
$len = $value !== null ? strlen($value) : 0;
This triggers when variables that could be null get passed to functions that expect a string or int. Common with database results where a column can be NULL.
7. String Arithmetic Operations (PHP 8.0)
// Used to work, now a TypeError in PHP 8
$total = "10" + "20abc"; // Previously: 30, now: TypeError
// FIXED — cast explicitly
$total = (int)"10" + (int)"20abc"; // 30
8. ReflectionParameter::getClass() (PHP 8.0)
Framework code often uses reflection. This method was removed:
// BROKEN
$class = $param->getClass();
// FIXED
$type = $param->getType();
if ($type instanceof ReflectionNamedType && !$type->isBuiltin()) {
$class = new ReflectionClass($type->getName());
}
How to Find All the Issues at Once
Option 1: PHP Compatibility Checker
Install php-compatibility with PHPCS:
composer global require squizlabs/php_codesniffer
composer global require phpcompatibility/php-compatibility
phpcs --standard=PHPCompatibility --runtime-set testVersion 8.0 /path/to/your/code
This scans your entire codebase and lists every compatibility issue with file and line number.
Option 2: Enable Error Logging First
If you can't run a static analysis tool, at minimum turn on error logging:
// In php.ini or .htaccess
error_reporting = E_ALL
log_errors = On
error_log = /var/log/php_errors.log
display_errors = Off // Don't show errors to users
Then trigger each page and check the log. You'll see exactly which functions are failing.
Option 3: Test on PHP 8 Before Migrating
If your host lets you change PHP version, set up a staging copy on PHP 8, run it for a week, and fix everything you find before switching production.
OpenCart-Specific PHP 8 Issues
OpenCart 2.x and early 3.x have several known PHP 8 breakages:
| Component | Issue | Fix |
|---|---|---|
| Session handling | each() in session code |
Update to OC 3.0.3.8+ |
| Image library | GD function signature changes | Update or replace image class |
| Extensions | Many use deprecated functions | Check each extension individually |
| Payment modules | Often use old mysqli style | Replace or update payment module |
For OpenCart specifically, the fastest approach is usually to upgrade to the latest 3.x patch release, then fix any remaining extension issues one by one.
When It's Faster to Pay Someone
If you have more than 10–15 files with PHP 8 issues — and especially if you have custom extensions or modifications — the audit-and-fix process can take 3–8 hours per site. Running phpcs first gives you the full list so you can make an informed decision.
I've done PHP 8 migrations on everything from small sites (2 hours) to heavily customised OpenCart stores (2 days). Tell me what platform you're on and roughly how many custom files you have — I'll give you an honest estimate.