Repository: codeigniter4/CodeIgniter4 (PHP)

Issue:
Bug: number_to_currency error on NumberFormatter::setAttribute() using default parameter values
### PHP Version

8.1

### CodeIgniter4 Version

4.1.5

### CodeIgniter4 Installation Method

Git

### Which operating systems have you tested for this bug?

Linux

### Which server did you use?

fpm-fcgi

### Database

_No response_

### What happened?

When use `number_to_currency()` in PHP 8.1, it will throw  `NumberFormatter::setAttribute(): Passing null to parameter #2 ($value) of type int|float is deprecated` exceptions. It doesn't occur on PHP 8.0.13 and older, much like problem discussed in #5371 because of PHP 8.1 disallow null type on non-nullable. It makes problem since `$fraction` is null by default and `NumberFormatter::setAttribute()` won't accept null variables.

### Steps to Reproduce

Simply call to `number_to_currency()` with default value

```
<?php

namespace App\Modules\Home\Controllers;

use App\Controllers\BaseController;

class Home extends BaseController
{
    public function index()
    {
        echo number_to_currency(1000000.00, 'IDR');
    }
}
```

### Expected Output

It should handle currency format as expected.

### Anything else?

Here's partial log trace of problematic functions
```
{
    trace: [
        {
            "function": "errorHandler",
            "class": "CodeIgniter\\Debug\\Exceptions",
            "type": "->"
        },
        {
            "file": "/home/thiekus/web/redacted/system/Helpers/number_helper.php",
            "line": 146,
            "function": "setAttribute",
            "class": "NumberFormatter",
            "type": "->"
        },
        {
            "file": "/home/thiekus/web/redacted/system/Helpers/number_helper.php",
            "line": 124,
            "function": "format_number"
        }
    ]
}
```


Discussion:
I've confirmed this bug.

```php
<?php
namespace App\Controllers;
class Home extends BaseController
{
    public function index()
    {
        helper('number');
        echo number_to_currency(1000000.00, 'IDR');
    }
}
```
```
ErrorException
NumberFormatter::setAttribute(): Passing null to parameter #2 ($value) of type int|float is deprecated search →
SYSTEMPATH/Helpers/number_helper.php at line 146
```

@thiekus Thank you for reporting.

I sent a PR to fix this: #5454




Patch:
diff --git a/system/Helpers/number_helper.php b/system/Helpers/number_helper.php
index b3d7c80c6006..35e748978fbb 100644
--- a/system/Helpers/number_helper.php
+++ b/system/Helpers/number_helper.php
@@ -112,11 +112,7 @@ function number_to_amount($num, int $precision = 0, ?string $locale = null)
 }
 
 if (! function_exists('number_to_currency')) {
-    /**
-     * @param string $locale
-     * @param int    $fraction
-     */
-    function number_to_currency(float $num, string $currency, ?string $locale = null, ?int $fraction = null): string
+    function number_to_currency(float $num, string $currency, ?string $locale = null, int $fraction = 0): string
     {
         return format_number($num, 1, $locale, [
             'type'     => NumberFormatter::CURRENCY,
diff --git a/user_guide_src/source/helpers/number_helper.rst b/user_guide_src/source/helpers/number_helper.rst
index eeca3a00614f..be5be2a8018c 100644
--- a/user_guide_src/source/helpers/number_helper.rst
+++ b/user_guide_src/source/helpers/number_helper.rst
@@ -27,7 +27,7 @@ Available Functions
 
 The following functions are available:
 
-.. php:function:: number_to_size($num[, $precision = 1[, $locale = null])
+.. php:function:: number_to_size($num[, $precision = 1[, $locale = null]])
 
     :param      mixed     $num: Number of bytes
     :param      int       $precision: Floating point precision
@@ -86,21 +86,23 @@ The following functions are available:
 
         echo number_to_amount('123,456,789,012', 2, 'de_DE'); // Returns 123,46 billion
 
-.. php:function:: number_to_currency($num, $currency[, $locale = null])
+.. php:function:: number_to_currency($num, $currency[, $locale = null[, $fraction = 0]])
 
-    :param mixed $num: Number to format
+    :param float $num: Number to format
     :param string $currency: The currency type, i.e., USD, EUR, etc
-    :param string $locale: The locale to use for formatting
+    :param string|null $locale: The locale to use for formatting
     :param integer $fraction: Number of fraction digits after decimal point
     :returns: The number as the appropriate currency for the locale
     :rtype: string
 
     Converts a number in common currency formats, like USD, EUR, GBP, etc::
 
-        echo number_to_currency(1234.56, 'USD');  // Returns $1,234.56
-        echo number_to_currency(1234.56, 'EUR');  // Returns €1,234.56
-        echo number_to_currency(1234.56, 'GBP');  // Returns £1,234.56
-        echo number_to_currency(1234.56, 'YEN');  // Returns YEN1,234.56
+        echo number_to_currency(1234.56, 'USD', 'en_US', 2);  // Returns $1,234.56
+        echo number_to_currency(1234.56, 'EUR', 'de_DE', 2);  // Returns 1.234,56 €
+        echo number_to_currency(1234.56, 'GBP', 'en_GB', 2);  // Returns £1,234.56
+        echo number_to_currency(1234.56, 'YEN', 'ja_JP', 2);  // Returns YEN 1,234.56
+
+    If you don't specify a locale, the Request locale is used.
 
 .. php:function:: number_to_roman($num)
 


Test patch:
diff --git a/tests/system/Helpers/NumberHelperTest.php b/tests/system/Helpers/NumberHelperTest.php
index 286440d7423b..006d0a650118 100755
--- a/tests/system/Helpers/NumberHelperTest.php
+++ b/tests/system/Helpers/NumberHelperTest.php
@@ -126,6 +126,7 @@ public function testQuadrillions()
      */
     public function testCurrencyCurrentLocale()
     {
+        $this->assertSame('$1,235', number_to_currency(1234.56, 'USD', 'en_US'));
         $this->assertSame('$1,234.56', number_to_currency(1234.56, 'USD', 'en_US', 2));
         $this->assertSame('£1,234.56', number_to_currency(1234.56, 'GBP', 'en_GB', 2));
         $this->assertSame("1.234,56\u{a0}RSD", number_to_currency(1234.56, 'RSD', 'sr_RS', 2));