Floats can't hold every integer exactly, so past a certain size a large integer converted to a float ends up slightly off. This RFC from Alexandre Daubois proposed two functions that tell you whether a value can be converted to a float or an int without losing precision.

Show me

The RFC's main example checks a price before encoding it as JSON. The number 9007199254740993 can't be stored exactly as a float, so the code converts it to a string instead:

$data = ['price' => 9007199254740993];

if (!is_representable_as_float($data['price'])) {
    $data['price'] = (string) $data['price'];
}

is_numeric() can't help here, because it tells you the value is a number, not whether it fits in a float.

How it works

The two functions would be:

function is_representable_as_float(mixed $value): bool
function is_representable_as_int(mixed $value): bool

is_representable_as_float() returns true for floats, and for ints or numeric strings that a float can represent exactly. Floats can hold every integer up to 2^53 - 1, but above that only some integers fit:

is_representable_as_float(2**53);     // true
is_representable_as_float(2**53 + 1); // false
is_representable_as_float(2**54 + 2); // true
is_representable_as_float(2**54 + 1); // false

is_representable_as_int() returns true for ints, for floats with no fractional part that fall inside the int range, and for strings holding such a whole number:

is_representable_as_int(42);        // true
is_representable_as_int(3.14);      // false
is_representable_as_int("123.456"); // false

Some results depend on the platform. For example, is_representable_as_int(2.0**31) is true on 64-bit systems but false on 32-bit ones.

Strings are parsed the same way is_numeric() parses them, and the decimal separator is always . regardless of locale. The author was unsure about the names, and alternatives included is_safe_float(), fits_float() and can_cast_to_float().

What it means for existing code

Nothing would break unless your code already declares a function with one of these names, and the author's GitHub search found none.

Where it stands

The author withdrew the RFC. A vote was set up on the page, but no votes were cast.