rector
rector copied to clipboard
[PHP 7.4] Replace deprecated money_format() with number_format()/NumberFormatter
This function was deprecatedin PHP 7.4
- https://github.com/php/php-src/commit/b1cdf06673789cf5c379e7af88c5af98bd06735c
This is tested and values are identical 1:1 in both version.
- $value = money_format('%i', $value);
+ $roundedValue = round($value, 2, PHP_ROUND_HALF_ODD);
+ $value = number_format($roundedValue, 2, '.', '');
Another way is using NumberFormatter
, but I could not figure it out:
- https://benedikt.gr/posts/2019-12-01-php-money-format-to-number_formatter/
@TomasVotruba it seems the result need to be checked against Locale
value, eg:
setlocale(LC_MONETARY, 'en_US');
echo money_format('%i', 11);
// output : USD 11.00
which we can't use only number_format()
as it not prepended with USD
for en_US
.
Oddly enough, I did this very change in someone's code yesterday using regex substitutions:
From:
setlocale(LC_MONETARY, 'en_US');
echo money_format( '%(n', ($rowm1['00001'])); // wrap output in () if negative
To:
$numFormatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY_ACCOUNTING);
echo $numFormatter->formatCurrency($rowm1['00001'], 'USD');
A lame, but working, test:
/**
* @test
*/
public function numberFormatterReturnsCorrectValue(): void
{
$this->assertSame(
'($123.46)',
formatIt(-123.45987887)
);
$this->assertSame(
'$123.46',
formatIt(123.45987887)
);
}
Some work in mapping the money_format()
format specifiers to the appropriateNumberFormatter
class constants. (You're welcome, says Captain Obvious.) I haven't figured out the rule-based formats yet.
@clarkphp could you write list of possible equivalent code from money_format() to NumberFormatter/number_format? Thank you.
Since I've not used either money_format()
or NumberFormatter
class much before this client's code migration, I'm not intimately familiar with their behaviour. So, I looked here for inspiration:
https://github.com/php/php-src/tree/master/ext/intl/tests (formatter_*.phpt)
https://github.com/php/php-src/blob/php-7.4.30/ext/standard/tests/strings (money*.phpt)
Some of that will be more useful than other parts, but the above, the manual pages, and some experimentation should yield format mappings to aid in rectorphp/rector-src#2727
I can't spend a lot of time on it all at once, but I can add mappings each day until it's deemed sufficient. Will that do?
@clarkphp thank you for the pointer, yes, that will do, we can improve with iteration PRs 👍 , not only in single PR for it
@TomasVotruba @clarkphp it seems we can use money_format_polyfill library for it, ref
https://github.com/boenrobot/money_format_polyfill
The result seems equals with apply setlocale()
usage https://3v4l.org/IGIr0
@samsonasik The polyfill can help in the worst cases, but in the end the upgrade path to current PHP features is more maintainable choice.
I'll have all the mappings I can do completed sometime this afternoon.
I'm not done with the mapping, and certainly not sending you a PR this morning, but to prove I'm doing something: https://gist.github.com/clarkphp/b2643a4c4a16cafd02bd85eba18a72dd
Thank you @clarkphp , that may need to be in invokable function to avoid out of scope variable make side effect.
Don't worry; don't read that code as if I think it close to what the rector/fixer would look like. That's just a scratchpad for figuring out the behavior of money_format() and NumberFormatter.
@samsonasik Just letting you know I'm still working on this. See experiments and output at https://gist.github.com/clarkphp/b2643a4c4a16cafd02bd85eba18a72dd
Modeling after your initial PR, I've got new code or modifications in:
- rector-src/rules/Php74/Rector/FuncCall/MoneyFormatToNumberFormatterRector.php
- rector-src/rules/Php74/Rector/FuncCall/MoneyFormatToNumberFormatterRector/config/configured_rule.php
- rector-src/rules-tests/Php74/Rector/FuncCall/MoneyFormatToNumberFormatterRector/Fixture/fixture.php.inc
- rector-src/rules-tests/Php74/Rector/FuncCall/MoneyFormatToNumberFormatterRector/MoneyFormatToNumberFormatterRectorTest.php
- rector-src/src/ValueObject/PhpVersionFeature.php
After work today, I may open a draft PR for your thoughts. I'll give CONTRIBUTING.md another thorough read, as well.
Thank you, code snippet with include in online code parser can be used to build closure for it, ref:
- https://github.com/rectorphp/rector-downgrade-php/blob/main/rules/DowngradePhp81/snippet/array_is_list_closure.php.inc
- https://github.com/rectorphp/rector-downgrade-php/blob/c5e04ca5255452f1f9fdab28b8a6bcb7676f24a0/rules/DowngradePhp81/Rector/FuncCall/DowngradeArrayIsListRector.php#L104