エラーの内容
Fatal error: Uncaught DivisionByZeroError: Division by zero in /path/to/script.php on line 12
PHP 8 ではゼロ除算の扱いが変わりました。PHP 7 では、ゼロで割ると Warning が発生するだけで処理は継続され、false を返して次へ進んでいました。PHP 8 では DivisionByZeroError がスローされ、スクリプトはその場で停止します。最近 PHP をアップグレードした場合、以前は「動いていた」コードが本番環境でクラッシュするのはこれが原因である可能性が高いです。
主な原因
0・null・空文字列(空文字列は0にキャストされる)を保持している変数で割り算をしている- 除数がゼロの場合のモジュロ演算子
%— 同じエラーが、別の演算子で起きる - ユーザー入力・データベースクエリ・設定ファイルなど、計算処理に渡る前にバリデーションされていない動的な除数
修正手順
1. 除算の前に除数をガードする
ほとんどの場合、シンプルな事前チェックだけで解決できます。割り算を行う前に除数がゼロでないことを確認してください。
<?php
// $count が 0 のときにクラッシュ — 例: 売上レポートでまだ注文がない場合
$average = $total / $count;
// 安全なバージョン
if ($count === 0) {
$average = 0; // または null、あるいはドメイン固有の例外をスロー
} else {
$average = $total / $count;
}
2. 1行で書く場合は三項演算子を使う
if/else ブロックが冗長に感じるときは、三項演算子でも同様に対処できます。
<?php
$average = $count !== 0 ? $total / $count : 0;
$remainder = $count !== 0 ? $total % $count : 0;
3. 浮動小数点除算には fdiv() を使う(PHP 8以降)
fdiv() は IEEE 754 に準拠しており、ゼロで割っても例外はスローされず、INF・-INF・NAN が返されます。除数ごとに分岐するより、不正な結果を後処理したい数値パイプラインで便利です。
<?php
$result = fdiv($total, $count); // $count === 0 の場合は INF を返す。例外はスローされない
if (!is_finite($result)) {
$result = 0;
}
4. 計算パイプラインで DivisionByZeroError をキャッチする
計算値のチェーンの途中など、事前に除数を確認しにくいケースもあります。try/catch を使えば、1つの計算が失敗してもアプリの残りの処理を継続できます。
<?php
try {
$rate = $processed / $total;
} catch (\DivisionByZeroError $e) {
error_log('Division by zero: ' . $e->getMessage());
$rate = 0;
}
5. 入力値はエントリーポイントでバリデーションする
ユーザー送信値・フォームの POST データ・データベースのカラムは、予期しないゼロの最も一般的な発生源です。計算ロジックに渡る前に弾いてください。
<?php
$count = (int) $_POST['count'];
if ($count 'count must be greater than zero']);
exit;
}
$average = $total / $count; // 安全 — $count は正の整数
6. ゼロによるモジュロ — 同じエラー、同じ対処法
% 演算子も同様に DivisionByZeroError をスローします。同じガードを、演算子を替えて適用してください。
<?php
// クラッシュする
$remainder = $value % $divisor;
// 安全な整数モジュロ
$remainder = $divisor !== 0 ? $value % $divisor : 0;
// 浮動小数点には fmod() を使う — ゼロ除算時は NAN を返す。例外はスローされない
$remainder = fmod($value, $divisor);
動作確認
以下を test_division.php として保存し実行して、修正が正しく機能していることを確認してください。
<?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
実行コマンド: php test_division.php。致命的エラーが出なければ修正完了です。
PHP 7 と PHP 8 の動作の違い
PHP 7 からアップグレードした場合、挙動が2点変わっています。
- PHP 7:
$x / 0はWarning: Division by zeroを発生させてfalseを返す。$x % 0はすでにDivisionByZeroErrorをスローする - PHP 8以降:
/と%の両方がDivisionByZeroErrorをスローする
false の戻り値だけをチェックしていた PHP 7 のコードは PHP 8 で壊れます。if ($divisor !== 0) によるガードは両バージョンで動作するため、こちらを使用してください。
クイックヒント
- 緩い比較
!= 0ではなく、厳密な比較!== 0を使うこと —nullや空文字列に対して緩い比較は予期しない動作をする場合があります - データベース由来の値は除算前に明示的にキャストする:
(int) $row['count']または(float) $row['amount'] intdiv()も除数がゼロの場合にDivisionByZeroErrorをスローする — 同じガードが適用されます- 本番環境では
display_errors = Offに設定してファイルにログを記録すること。スタックトレースをエンドユーザーに漏らさないようにしてください

