In PHP 8.5, what do 7 / 2, 6 / 2, 1 / 0 and -2 ** 2 evaluate to, and why?
answer
- / returns int only when exact
- DivisionByZeroError since PHP 8.0
- an Error, not an Exception
- ** binds tighter than unary minus
- ** is right-associative
basics
~20 s7 / 2 is float(3.5) and 6 / 2 is int(3), because / returns an int only when two ints divide exactly; 1 / 0 throws DivisionByZeroError since PHP 8.0; -2 ** 2 is int(-4) because ** binds tighter than unary minus.
solid answer
~40 sThe `/` operator returns an `int` only when both operands are ints (or numeric strings juggled to ints) and the division is exact, so `6 / 2` is `int(3)` and `7 / 2` is `float(3.5)`. Dividing by zero, `1 / 0` or `1 / 0.0`, throws `DivisionByZeroError` with the message `Division by zero` since PHP 8.0; PHP 7 emitted a warning and returned `INF` or `NAN`. That class extends `ArithmeticError` and `Error`, so `catch (Exception $e)` does not catch it. The `**` operator binds tighter than unary minus and is right-associative: `-2 ** 2` is `-(2 ** 2)`, `int(-4)`, and `2 ** 3 ** 2` is `2 ** 9`, `512`. `**` on ints stays an `int` unless the exponent is negative or the result overflows, in which case it becomes a `float`.
code
php · 16 lines<?php
declare(strict_types=1);
function averageDiscount(int $totalDiscount, int $redemptions): float
{
return $totalDiscount / $redemptions;
}
try {
averageDiscount(500, 0);
} catch (Exception $e) {
echo 'never reached', PHP_EOL;
} catch (DivisionByZeroError $e) {
echo get_class($e), ': ', $e->getMessage(), PHP_EOL;
}
// DivisionByZeroError: Division by zerogo deeper
Recall that / may return an int or a float, that ** is exponentiation, and that dividing by zero throws on PHP 8.
Explain the result-type rule for /, the Error hierarchy behind DivisionByZeroError, and why ** binds tighter than unary minus and groups from the right.
Audit data-driven divisions and catch blocks when upgrading from PHP 7, and make typed returns explicit instead of relying on / returning an int.
Decide where numeric edge cases are handled across services: validation at the boundary, domain rules for empty denominators, or a shared arithmetic helper.
## The division operator PHP has a single `/` operator for both integer and floating-point operands, and its result type depends on the values: | Expression | Result | Why | |---|---|---| | `6 / 2` | `int(3)` | both ints and the numerator is a multiple of the divisor | | `7 / 2` | `float(3.5)` | both ints but not exact | | `6.0 / 2` | `float(3)` | a float operand makes the result a float | | `"6" / "2"` | `int(3)` | numeric strings are juggled to ints first | This surprises people who expect C-style integer division (`7 / 2 == 3`) or who expect `/` to always return a float. When the type matters, for example before a strict `===` check or a typed return, cast the result or use the dedicated integer and float division functions, which are a separate topic. ## Division by zero in PHP 8 PHP 8.0 reclassified many engine warnings as exceptions. Division by zero is one of them: - **PHP 7**: `1 / 0` raised a warning and returned `INF`, `-INF` or `NAN`, and execution continued with a poisoned value. - **PHP 8.0 and later**: `1 / 0` and `1 / 0.0` throw `DivisionByZeroError` with the message `Division by zero`. Two details matter in production code: 1. `DivisionByZeroError` extends `ArithmeticError`, which extends `Error`. It is a `Throwable` but **not** an `Exception`, so a `catch (Exception $e)` block misses it. Catch `DivisionByZeroError`, `ArithmeticError` or `Throwable`, or better, check the divisor first. 2. The check is at runtime, including for literal expressions, so a divisor that comes from data (an empty cart's item count, a zero-rated coupon) now stops the request instead of silently printing `INF`. ## The exponent operator `**` (and its assignment form `**=`) raises the left operand to the power of the right. Its place in the precedence table causes most of the interview puzzles: - **It binds tighter than unary minus.** `-2 ** 2` is `-(2 ** 2)`, which is `int(-4)`. Write `(-2) ** 2` for `4`. - **It is right-associative.** `2 ** 3 ** 2` is `2 ** (3 ** 2)`, which is `2 ** 9`, `int(512)`, not `(2 ** 3) ** 2 = 64`. - **It binds tighter than casts and `++`/`--`.** In the precedence table `**` sits above the unary row, just below `clone` and `new`. The result type follows the operands: | Expression | Result | |---|---| | `2 ** 10` | `int(1024)` | | `2 ** -1` | `float(0.5)`: a negative exponent always yields a float | | `2 ** 63` on a 64-bit build | `float`: the int result would overflow | | `2.0 ** 2` | `float(4)` | | `0 ** -1` | `float(INF)` plus a deprecation since PHP 8.4 | PHP 8.4 deprecated raising `0` to a negative power (with both `**` and `pow()`), because it is equivalent to dividing by zero; the new `fpow()` function gives IEEE 754 semantics when that is what you want. ## Putting it together A typical interview snippet combines these: ```php var_dump(7 / 2); // float(3.5) var_dump(6 / 2); // int(3) var_dump(-2 ** 2); // int(-4) var_dump(2 ** 3 ** 2); // int(512) ``` and then asks what `1 / 0` does. On PHP 8.5 the answer is an uncaught `DivisionByZeroError` unless a handler for `Error` or `Throwable` catches it. ## Practical guidance - Guard divisors that come from data, and decide what an empty denominator means for the business rule. - Do not rely on `/` returning an `int`; cast explicitly when a type is required. - Parenthesise negative bases in exponent expressions. - When upgrading from PHP 7, search for code that relied on `INF` after a division by zero.
- Why does -2 ** 2 give -4 while (-2) ** 2 gives 4?In PHP's precedence table `**` sits above unary minus, so `-2 ** 2` is read as `-(2 ** 2)`: square first, then negate. Parentheses make `-2` the base, so `(-2) ** 2` is `4`. The same rule makes `-$x ** 2` negative for any non-zero `$x`, a common bug in variance or distance formulas.
- What did 1 / 0 do before PHP 8, and what breaks on upgrade?PHP 7 emitted a `Division by zero` warning and returned a float `INF`, `-INF` or `NAN`, and the script continued. Since PHP 8.0 the same expression throws `DivisionByZeroError`. Code that divided by a data-driven count and relied on the warning, or that only catches `Exception`, now fails with an uncaught error.
saying these in an interview costs you the question
- Says 7 / 2 is int(3) because both operands are integers.
- Believes 1 / 0 still returns INF with a warning on PHP 8.
- Catches DivisionByZeroError with catch (Exception $e).
- Reads -2 ** 2 as (-2) ** 2 and answers 4.
- Thinks ** is left-associative, so 2 ** 3 ** 2 is 64.