Search code examples
phpformatnumber-formattingnumberformatterformat-currency

Why does PHP give me a fatal error for sending the (according to the manual) correct arguments to NumberFormatter's format()?


From the manual at: https://www.php.net/manual/en/numberformatter.format.php

public NumberFormatter::format ( int|float $value , int $type = ? ) : string

This code:

$a = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY);
$string = $a->format(123, \NumberFormatter::TYPE_CURRENCY);
var_dump($string);

Causes this:

PHP Fatal error:  Uncaught ValueError: NumberFormatter::format(): Argument #3 must be a NumberFormatter::TYPE_* constant

Huh? Argument #3? There is no argument #3 (except in the procedural version)! And this code (thinking that maybe the documentation is wrong and nobody has ever spotted it before now):

$a = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY);
$string = $a->format(123, 'USD', \NumberFormatter::TYPE_CURRENCY);
var_dump($string);

But it just causes this:

PHP Fatal error:  Uncaught ArgumentCountError: NumberFormatter::format() expects at most 2 arguments, 3 given

Okay... So how do you want it, PHP? Is it 3 or 2? I'm lost at this point.

Important: The reason I'm not using formatCurrency even though it is definitely a currency number, is that (in the real code) I'm trying to remove the currency symbol but otherwise format it as a currency. formatCurrency sadly ignores the setSymbol, but format honors it. That's why format is used in this case. Thus, please don't tell me to use formatCurrency.


Solution

  • It appears that the documentation on the intl extension is a little incomplete or misleading. It would seem that calling format() without the second type argument will produce the output you want on your NumberFormatter::CURRENCY object:

    $a = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY);
    echo $string = $a->format('123');
    // $123.00
    
    $a = new \NumberFormatter('en_GB', \NumberFormatter::CURRENCY);
    echo $string = $a->format('123');
    // £123.00
    

    The docs show that argument as optional but do not apparently explain how or when it should be used. In this case, omitting it seems to do the job.