개발하다 보면 갑자기 화면에 "Warning: Division by zero"라는 경고 메시지가 떠본 경험이 있을 텐데, 대부분의 개발자들은 이 경고를 무시하거나 임시로 조건문을 붙여 넘어가곤 한다. 다만 이 경고가 정확히 무엇인지, 왜 발생하는지, 어떻게 근본적으로 해결해야 하는지를 모르는 경우가 많다. 이번에는 Division by zero 에러의 정확한 원인부터 실무에서 써먹을 수 있는 완벽한 해결 방법까지 정리해서 소개하겠다.

 

Division by zero 에러란 무엇인가
zero division(영: 0으로 나누기)은 수학에서 불가능한 연산이다. 0으로 나누는 행위는 정의되지 않기 때문에 PHP는 경고를 발생시키고, 결과값으로 INF(무한대) 또는 NAN(숫자가 아님)을 반환한다. 실무에서는 사용자 입력값, API 응답값, 데이터베이스 조회 결과 등이 예상과 달리 0이 되면서 이 오류가 발생한다.

예를 들어 총 판매수량으로 평균 매출액을 계산하는 상황을 떠올려보자. 보통은 매출액 / 판매수량을 계산하는데, 만약 그 날 판매가 0건이라면? Division by zero 경고가 발생하고 논리 오류가 생긴다.

 

실전 예제로 문제 파악하기
✗ 잘못된 코드 - 경고 발생
<?php
$total_revenue = 50000;
$total_quantity = 0;  // 판매 0건

$average = $total_revenue / $total_quantity;
echo "평균 매출액: " . $average;
?>

이 코드를 실행하면 "Warning: Division by zero"가 뜨고, $average에는 INF(무한대) 값이 저장된다. 그 다음 줄에서 echo로 출력하려니 "INF"가 화면에 표시되어 사용자 입장에서는 이상한 값을 보게 된다.

 

✓ 올바른 코드 - 조건 검증
<?php
$total_revenue = 50000;
$total_quantity = 0;

if ($total_quantity != 0) {
    $average = $total_revenue / $total_quantity;
    echo "평균 매출액: " . $average;
} else {
    echo "판매 데이터가 없습니다.";
}
?>

사전에 분모가 0인지 확인하고, 0이면 안전한 메시지를 출력한다. 경고도 발생하지 않고, 사용자에게도 명확한 정보를 전달할 수 있다.

 

실무에서 자주 마주치는 상황
상황 1) API 응답값이 예상과 다를 때
<?php
// 외부 API에서 데이터를 받는다
$response = json_decode(file_get_contents('https://api.example.com/stats'), true);

// 응답이 비정상이거나 특정 필드가 0이면?
$success_rate = $response['success_count'] / $response['total_count'];
echo $success_rate * 100 . "%";
?>

위 코드는 API가 total_count를 0으로 반환하면 Division by zero 에러가 난다. 해결책은 간단하다.

<?php
$response = json_decode(file_get_contents('https://api.example.com/stats'), true);

$total_count = $response['total_count'] ?? 0;
if ($total_count > 0) {
    $success_rate = $response['success_count'] / $total_count;
    echo round($success_rate * 100, 2) . "%";
} else {
    echo "데이터 없음";
}
?>

null 병합 연산자(??)로 기본값을 설정하고, 명시적으로 >0 조건을 확인한다. 이렇게 하면 API 응답이 비정상이더라도 안전하다.

상황 2) 데이터베이스 COUNT 결과가 0일 때
<?php
$pdo = new PDO('mysql:host=localhost;dbname=shop', 'user', 'password');

$stmt = $pdo->query('SELECT COUNT(*) as cnt FROM orders WHERE status = "cancelled"');
$count = $stmt->fetch(PDO::FETCH_ASSOC)['cnt'];

// count가 0이면 Division by zero 발생
$cancel_ratio = $count / 100;
echo "취소율: " . $cancel_ratio;
?>

안전한 버전:

<?php
$pdo = new PDO('mysql:host=localhost;dbname=shop', 'user', 'password');

$stmt = $pdo->query('SELECT COUNT(*) as cnt FROM orders');
$total = $stmt->fetch(PDO::FETCH_ASSOC)['cnt'];

if ($total > 0) {
    $stmt = $pdo->query('SELECT COUNT(*) as cnt FROM orders WHERE status = "cancelled"');
    $count = $stmt->fetch(PDO::FETCH_ASSOC)['cnt'];
    $cancel_ratio = ($count / $total) * 100;
    echo "취소율: " . round($cancel_ratio, 2) . "%";
} else {
    echo "주문 데이터가 없습니다.";
}
?>

 

재사용 가능한 유틸리티 함수 만들기

매번 조건문을 붙이는 건 번거롭다. 실무에서는 이렇게 안전한 나눗셈 함수를 만들어 쓰는 게 낫다.

<?php
/**
 * 안전한 나눗셈 함수
 * @param float $dividend 피제수
 * @param float $divisor 제수
 * @param float $default_value divisor가 0일 때 반환할 기본값
 * @return float 계산 결과 또는 기본값
 */
function safe_divide($dividend, $divisor, $default_value = 0) {
    if ($divisor == 0 || !is_numeric($dividend) || !is_numeric($divisor)) {
        return $default_value;
    }
    return $dividend / $divisor;
}

// 사용 예
$total_revenue = 50000;
$total_quantity = 0;

$average = safe_divide($total_revenue, $total_quantity, 0);
echo "평균: " . $average;  // 평균: 0 (경고 없음)

// 백분율 계산
$cancel_count = 0;
$total_count = 150;
$cancel_percent = safe_divide($cancel_count, $total_count, 0) * 100;
echo "취소율: " . round($cancel_percent, 2) . "%";  // 취소율: 0%
?>

이 함수를 프로젝트의 공통 utility 파일에 넣어두면, 어디서나 안전하게 나눗셈을 할 수 있다.

 

흔한 실수와 올바른 해결법
실수 문제점 올바른 방법
@$a / $b (@ 오류 억제) 경고는 숨지만 논리 오류는 여전하고, 성능 저하 가능 사전 조건 검증: if ($b != 0) { ... }
$result = $a / ($b ?: 1) 0 대신 1로 나누므로 결과값이 왜곡됨 기본값을 명시적으로 정의: if ($b > 0) { ... } else { $result = 0; }
is_numeric($b) 만 체크 문자열 "0"도 통과하여 잘못된 결과 생성 is_numeric() && $b != 0 둘 다 체크
에러 로깅 없음 나중에 버그 추적이 어려움 error_log()나 전용 로거로 기록: error_log("Division by zero attempt: $a / $b");

 

고급: PHP 8.0+ 매칭(Match) 문법으로 안전하게

PHP 8.0 이상을 사용한다면 match 문법으로 더 깔끔하게 처리할 수 있다.

<?php
$total_revenue = 50000;
$total_quantity = 0;

$result = match(true) {
    $total_quantity > 0 => $total_revenue / $total_quantity,
    default => 0
};

echo "결과: " . $result;
?>

이 방식은 조건을 명확히 표현하고, if-else 중첩을 피할 수 있어 가독성이 좋다.

 

정리 및 다음 단계

Division by zero는 PHP의 기본 수학 규칙이 아니라 논리적 실수에서 비롯된 문제다. 경고 메시지를 억제하는 것보다 사전에 조건을 검증하는 습관이 훨씬 중요하다. 안전한 나눗셈 함수를 하나 만들어 프로젝트 전체에서 재사용하면, 같은 실수를 반복하지 않을 수 있다. 이 글의 safe_divide() 함수를 참고해 자신의 유틸리티 파일에 추가하고, 앞으로는 모든 나눗셈 연산 전에 분모 검증을 습관화하면, 예상치 못한 에러로 인한 서비스 중단을 크게 줄일 수 있을 것이다.