Number::parse

Parses a locale-formatted numeric string into an int or float using the intl NumberFormatter.

Signature
static Number::parse(string $string, ?int $type = NumberFormatter::TYPE_DOUBLE, ?string $locale = null): int|float|false
  • Added in Laravel 12.15.0

Parameters

ParameterTypeDescription
$$stringstringThe formatted string to read, written in the conventions of the target locale.
$$typeoptionalint|null= NumberFormatter::TYPE_DOUBLEA NumberFormatter TYPE_* constant choosing the PHP type the result is coerced to — TYPE_DOUBLE, TYPE_INT32 or TYPE_INT64.
$$localeoptionalstring|null= nullLocale whose separators are used. Falls back to the default locale set by Number::useLocale(), which starts as "en".

Return value

int|float|falseThe parsed number, as an int when $type is an integer constant and a float otherwise, or false when the string contains no leading number.

Errors

Throws a RuntimeException when the "intl" PHP extension is not loaded.

Changelog

  • PHP 12.15.0Added alongside Number::parseInt() and Number::parseFloat().
  • PHP 12.31.0The declared return type was widened to int|float|false so an unparseable string reports failure instead of tripping a return type error.

Number::parse() is the inverse of Number::format(). It hands the string to an intl NumberFormatter in DECIMAL mode, so grouping separators and the decimal mark are interpreted according to the locale rather than PHP's own rules. That is the whole point: (float) '1.234,56' gives you 1.234, because PHP reads the longest numeric prefix and treats the dot as a decimal point, while Number::parse('1.234,56', locale: 'de') gives you 1234.56.

When to reach for it

Use it on the boundary where locale-formatted text enters your system — a number typed into a form by a user whose browser locale is not English, a CSV exported from a European spreadsheet, a value scraped from a rendered page. Do not use it on machine-readable input such as JSON or a database column; those are already canonical and a plain cast is faster and stricter.

What trips people up

The formatter is lenient. It reads the longest numeric prefix it can and stops, so trailing junk is silently ignored rather than rejected. It also never throws for bad input — it returns false, which is easy to confuse with a legitimately parsed 0.

Number::parseInt() and Number::parseFloat() are thin wrappers that pin $type to TYPE_INT32 and TYPE_DOUBLE. Reach for parse() directly only when you need TYPE_INT64 or want the type to be decided at runtime.

Example

Example · php
<?php

use Illuminate\Support\Number;

// Default locale is "en": "," groups, "." is the decimal point.
var_dump(Number::parse('1,234.56'));

// German conventions: "." groups, "," is the decimal point.
var_dump(Number::parse('1.234,56', locale: 'de'));

// TYPE_INT32 truncates the fractional part instead of rounding it.
var_dump(Number::parse('1,234.56', NumberFormatter::TYPE_INT32));

// No leading number at all, so parsing fails.
var_dump(Number::parse('abc'));

// Output:
// float(1234.56)
// float(1234.56)
// int(1234)
// bool(false)

When to use it

  • Reading a quantity a user typed as "1.234,56" in a German-language form back into a float.
  • Importing a CSV exported from a locale-aware spreadsheet where thousands are separated by spaces or dots.
  • Turning a displayed total back into a number when the only value available is the already-formatted string.

Frequently asked questions

Why does Number::parse return false?

It returns false when the string has no leading number the locale's formatter can read, such as 'abc' or an empty string. It does not return false merely because there is trailing text — '12abc' parses to 12.0 — and it never returns null, so test the result with === false rather than is_null() or a falsy check.

What is the difference between Number::parse, parseInt and parseFloat?

parseInt and parseFloat are one-line wrappers that call parse() with $type fixed to NumberFormatter::TYPE_INT32 and NumberFormatter::TYPE_DOUBLE. Call parse() directly only when you need a different constant, such as TYPE_INT64 for values beyond 2,147,483,647, or when the desired type is decided at runtime.

Does Number::parse need the intl extension?

Yes. It calls ensureIntlExtensionIsInstalled() first and throws a RuntimeException naming the method if ext-intl is missing, because the parsing is done by PHP's NumberFormatter class. Install php-intl on the machine, and note that it is required at parse time, not just for formatting output.

More examples

parseInt and parseFloat pin the type for you

Both wrappers call parse() with a fixed $type. The two integer results show why the locale matters even when the digits look identical: in "en" the string "10.123" is ten-point-one-two-three and in "fr" the string "10,123" is the same value, and TYPE_INT32 truncates both to 10 — it is not reading "10,123" as ten thousand one hundred twenty-three.

Example · php
<?php

use Illuminate\Support\Number;

var_dump(Number::parseInt('10.123'));
var_dump(Number::parseInt('10,123', locale: 'fr'));
var_dump(Number::parseFloat('10'));
var_dump(Number::parseFloat('10.123'));

// Output:
// int(10)
// int(10)
// float(10)
// float(10.123)

Validating locale-formatted form input

The request keeps the raw string through validation, then converts it once using the authenticated user's locale so a French customer can type "1 234,50" and a US customer "1,234.50". The === false check is what catches unparseable input; a truthiness check would reject a legitimate zero.

Example · php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Number;

class StoreInvoiceLineRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'amount' => ['required', 'string'],
        ];
    }

    protected function passedValidation(): void
    {
        $amount = Number::parse(
            $this->string('amount')->trim()->value(),
            locale: $this->user()->locale,
        );

        if ($amount === false) {
            abort(422, 'The amount could not be read as a number.');
        }

        $this->merge(['amount' => $amount]);
    }
}

Round-tripping through format()

Formatting and parsing under the same locale returns the original value in every case, including en_IN with its lakh/crore grouping and fr with its non-breaking space separator. The round trip only holds when both calls use the same locale — parse the fr string as en and you get 9.0.

Example · php
<?php

use Illuminate\Support\Number;

$value = 9876543.21;

foreach (['en', 'de', 'fr', 'en_IN'] as $locale) {
    $formatted = Number::format($value, locale: $locale);
    $parsed = Number::parse($formatted, locale: $locale);

    printf("%-6s %-14s -> %s%s", $locale, $formatted, var_export($parsed, true), PHP_EOL);
}

// Output:
// en     9,876,543.21   -> 9876543.21
// de     9.876.543,21   -> 9876543.21
// fr     9 876 543,21   -> 9876543.21
// en_IN  98,76,543.21   -> 9876543.21

Discussion

  • Be the first to comment on this lesson.