The Error
Fatal error: Uncaught DivisionByZeroError: Division by zero in /path/to/script.php on line 12
PHP 8 changed how division by zero is handled. In PHP 7, dividing by zero triggered a Warning and execution continued โ returning false and moving on. PHP 8 turns it into a thrown DivisionByZeroError, and your script stops dead. If you upgraded recently, that's likely why something that "worked" before is now crashing in production.
Root Causes
- Dividing by a variable that holds
0,null, or an empty string (empty strings cast to0) - The modulo operator
%with a zero divisor โ same error, different operator - Dynamic divisors from user input, database queries, or config files that weren't validated before reaching the math
Step-by-Step Fix
1. Guard the divisor before dividing
Nine times out of ten, a simple pre-check is all you need. Verify the divisor isn't zero before you divide.
<?php
// Crashes when $count is 0 โ e.g. no orders yet in a sales report
$average = $total / $count;
// Safe version
if ($count === 0) {
$average = 0; // or null, or throw a domain-specific exception
} else {
$average = $total / $count;
}
2. Use a ternary for one-liners
When a full if/else block feels heavy, a ternary works just as well:
<?php
$average = $count !== 0 ? $total / $count : 0;
$remainder = $count !== 0 ? $total % $count : 0;
3. Use fdiv() for float division (PHP 8+)
fdiv() follows IEEE 754: divide by zero and you get INF, -INF, or NAN โ never an exception. It's handy in numeric pipelines where you'd rather handle bad results afterward than branch on every divisor upfront.
<?php
$result = fdiv($total, $count); // returns INF if $count === 0, never throws
if (!is_finite($result)) {
$result = 0;
}
4. Catch DivisionByZeroError in calculation pipelines
Sometimes you can't easily check the divisor in advance โ inside a chain of computed values, for instance. A try/catch keeps the rest of your app running even if one calculation blows up.
<?php
try {
$rate = $processed / $total;
} catch (\DivisionByZeroError $e) {
error_log('Division by zero: ' . $e->getMessage());
$rate = 0;
}
5. Validate dynamic input at the entry point
User-submitted values, form POST data, and database columns are the most common source of surprise zeros. Reject them before they ever reach your math logic.
<?php
$count = (int) $_POST['count'];
if ($count 'count must be greater than zero']);
exit;
}
$average = $total / $count; // safe โ $count is positive
6. Modulo by zero โ same error, same fix
The % operator throws DivisionByZeroError too. Same guard, different operator:
<?php
// Crashes
$remainder = $value % $divisor;
// Safe integer modulo
$remainder = $divisor !== 0 ? $value % $divisor : 0;
// For floats, use fmod() โ returns NAN on zero divisor, never throws
$remainder = fmod($value, $divisor);
Verification
Save this as test_division.php and run it to confirm the fix holds:
<?php
$total = 100;
$count = 0;
$average = $count !== 0 ? $total / $count : 0;
echo "Average: $average\n"; // Average: 0
$result = fdiv($total, $count);
echo "fdiv result: $result\n"; // fdiv result: INF
echo "is_finite: " . (is_finite($result) ? 'yes' : 'no') . "\n"; // no
Run it: php test_division.php. No fatal error means you're good.
PHP 7 vs PHP 8 Behavior
Upgrading from PHP 7? The behavior shifted in two ways:
- PHP 7:
$x / 0emitsWarning: Division by zeroand returnsfalse;$x % 0already throwsDivisionByZeroError - PHP 8+: both
/and%throwDivisionByZeroError
PHP 7 code that only checked for a false return value will break on PHP 8. The if ($divisor !== 0) guard works on both versions โ use that instead.
Quick Tips
- Use strict comparison
!== 0, not loose!= 0โ loose comparison can behave unexpectedly withnulland empty strings - Cast database-sourced values explicitly before dividing:
(int) $row['count']or(float) $row['amount'] intdiv()also throwsDivisionByZeroErroron a zero divisor โ the same guard applies- Set
display_errors = Offin production and log to a file; stack traces should never leak to end users

