格式钱 number_format PHP

Format money number_format PHP

我正在尝试将欧元格式化为拉丁美洲国家。但是我不能让所有的格式都正确。

这两行工作正常:

$currencies['ESP'] = array(2, ',', '.'); // Euro
$currencies['USD'] = array(2, '.', ','); // US Dollar

不起作用的是这些:

  1. 墨西哥我有$1,800,520墨西哥比索,我想得到这个 结果 $ 3,698.00

    $currencies['MXN'] = array(3, ",", '.'); // México Peso
    
  2. 哥伦比亚 $2,097,106.36 哥伦比亚比索 我想得到 $ 104,637,255.96

    $currencies['COP'] = array(2, ',', '.'); // Colombiano Peso
    
  3. 阿根廷 $53,609.02 阿根廷比索 我要得到 $10,490

    $currencies['ARS'] = array(2, ',', '.'); // Argentina Peso
    

有谁知道我做错了什么?感谢您的帮助。

我的函数示例:

/**
* @param self::$curr
* @return string
*/
public static function setCurrency($tipo) {
    // Creamos tipo moneda
    $tipoMoneda = ($tipo =='') ? self::$curr : $tipo;

    $moneda = match ($tipoMoneda) {
        'CLF' => "$",
        'COP' => "$",
        'ARS' => "$",
        'USD' => "$",
        'EUR' => "€",
        'MXN' => "$",
    };      
    return $moneda;
}   

/**
* Format price
* @param string
* @param string
*/
public static function toMoney($price,$tipo='') {
    $currencies['EUR'] = array(2, ',', '.'); // Euro
    $currencies['ESP'] = array(2, ',', '.'); // Euro
    $currencies['USD'] = array(2, '.', ','); // US Dollar
    $currencies['COP'] = array(2, ',', '.'); // Colombian Peso
    $currencies['MXN'] = array(3, ",", '.'); // Mexico Peso
    $currencies['CLP'] = array(0,  '', '.'); // Chilean Peso
    $currencies['ARS'] = array(2, ',', '.'); // Argentina Peso

    if ($tipo == '') :
        $money_format = number_format($price, ...$currencies[self::$curr]) . ' ' . self::setCurrency($tipo);
    else:
        $money_format = self::setCurrency($tipo) . number_format($price, ...$currencies[$tipo]);
    endif;
    return $money_format; 
} 

编辑: 我从数据库中得到的汇率

/**
* Calcular TAXES about original price base
* @param string
* @return string
*/
public static function CalcIva($valor, $arr =[]) {      
            
    // Get default IVA o by (USD-MXN) (COOKIE)
    $getIva = self::$defaultIva;
    
    // Price original
    $price = $valor;
    // Get taxes
    $iva = ($getIva / 100) * $price; 
    // Sum taxes to base price
    $precio = $price + $iva;    

    // On this line if $arr is not null i calculate 1.13 or some else x price
    if ($arr != null) : 
        // Calcul exchange rate (example: 1.13 * 20)
        $precio = $arr['cambio'] * $price;
    endif;
    // Price
    return $precio;     
 }

Example

我在 JS 上设置 cookie

/**
 * Select money (header)
 */
let moneda = document.getElementById('slc-moneda');
moneda.addEventListener('change', function (e) {
  // Get value option
  let tipo = this.value;
    // Not null
    if (tipo != 0) {
      // Value default, delete cookie
      if (tipo == 'EUR-ES') {
        // Eliminamos cookie, usamos configuracion por defecto
        delCookie('moneda');
        location.reload()
      // Set cookie - new money format
      } else {
        setCookie('moneda', tipo, 365)
        location.reload()     
      } 
    }          
    e.preventDefault()
  })

作为根据我之前的评论添加的背景信息,如果您在分离所有相互关联的问题并将所有部分放在一起时遇到困难,(我不知道您是否如此);这是我过去用来解决类似问题的一些代码。我已经根据您的 datamodel/code 进行了调整,并添加了一些评论:


就我个人而言,由于将一半的货币信息保存在数据库中而另一半保存在代码中似乎很混乱,我会向您的 monedas 数据库添加 4 列 table;即(例如 'Ecuador'):

`currency_symbol`     => '$'
`decimal_separator`   => '.'
`thousands_separator` => ','
`decimals`            => 2

接下来您要决定在 PHP 中使用什么数据类型作为价格值。 我猜它们在你的数据库中是 DECIMALs,在这种情况下,你可以在 PHP 中使用字符串 ('65.99') 或浮点数 (65.99);通常 string 是首选,因为它不会受到浮点数给 table.

带来的所有奇怪的影响

或者,您可以选择在数据库中以 cents 存储价格,这样您就可以在两者中使用 INTEGERs (6599)数据库和 PHP.

假设您在数据库中使用 DECIMAL,在 PHP 中使用 string;这样您就可以使用 PHP BCMath 函数来可靠地执行计算。 我们还假设您数据库中的所有价格始终代表相同的货币(例如:您公司的当地货币,假设它是 EUR)。


由于价格在您的网上商店式应用程序中是一个复杂的值,因此您需要一个简单的值 class 来定义它们。

class Price {
    private $value;

    public function __construct($value) {
        $value = trim((string) $value);
        if (!is_numeric($value) || preg_match('#^(\-)?([0-9]+)(\.[0-9]{1,2})?$#D', $value) !== 1) throw Exception('Invalid price value');
        $this->value = $value;
    }

    public function getRawValue() {
        return $this->value;
    }

    // When printing a price (using echo for example), print it in its converted form (defined later)
    public function __toString() {
        return PriceLocalization::displayLocalPrice( $this );
    }
}

接下来,您需要一个对象来保存(或缓存)有关所有货币的所有信息:

class Currencies {
    protected static $data = null;

    protected static function pullData() {
        if (is_null(static::$data)) {
            $data = [];
            // Pull the currency/priceconversion info from the DB
            $rows = run_your_dbquery('SELECT * FROM `monera`');
            foreach ($rows as $row) {
                $row['id_moneda'] = (int) $row['id_moneda'];
                $row['decimals']  = (int) $row['decimals'];
                $data[( $row['id_moneda'] )] = $row;
            }
            // Cache the data incase we have to do more conversions on the current page
            static::$data = $data;
        }
        return static::$data;
    }

    // Returns the entire table of currency/priceconversion info from the DB
    public static function getAll() {
        return static::pullData();
    }

    // Returns one record out of the table of currency/priceconversion info (or exception if invalid)
    public static function getSpecific($id) {
        $data = static::pullData();
        if (array_key_exists($id, $data)) return $data[$id];
        throw new Exception('Bad input');
    }
}

另一个对象处理用户能够 select 会话范围内的货币

class UserCurrencySelection {

    // store the users choice in $_COOKIE or $_SESSION or the like (used by your currency-selection selectbox)
    public static function setUserPreference($choice) {
        $_SESSION['currencychoice'] = $choice;
        return true;
    }

    // read the raw value from $_COOKIE or $_SESSION or the like (if any)
    public static function getUserPreference() {
        return ($_SESSION['currencychoice'] ?? null);
    }

    // get either the active currency's record (if any), or otherwise the default record (throw exception if neither exists)
    public static function getActive() {
        try {
            if ($current = static::getUserPreference()) {
                return Currencies::getSpecific( $current );
            }
        } catch (Exception $e) {}
        return Currencies::getSpecific( 5 ); // <-- the id of the "default" currency (in this case 5 = EUR)
    }
}

最后,class 将一切联系在一起

class PriceLocalization {

    // display a specific price adjusted to the -active- currency (with the default currency as fallback)
    public static function displayLocalPrice(Price $price, array $style=[]) {
        $currencyinfo = UserCurrencySelection::getActive();
        return static::displayPriceAs($price, $currencyinfo, $style);
    }

    // display a specific price adjusted to a -specific- currency (eg: id=3 gives colombian price)
    public static function displayPriceInCurrency(Price $price, $id, array $style=[]) {
        $currencyinfo = Currencies::getSpecific( $id );
        return static::displayPriceAs($price, $currencyinfo, $style);
    }

    // perform the actual conversion and formatting
    protected static function displayPriceAs(Price $price, array $currencyinfo, array $style=[]) {
        /* $currencyinfo = [
          'id_monera'           => 4, 
          'moneda'              => 'USD',
          'pais'                => 'Ecuador',
          'ido'                 => 'EC',
          'cambio'              => '1.13',
          'impuesto'            => '12',
          'currency_symbol'     => '$',
          'decimal_separator'   => '.',
          'thousands_separator' => ',',
          'decimals'            => 2,
        ]; */
        // the original price:
        $value_src      = $price->getRawValue();                    
        // Multiply the original price with the conversion rate (`cambio`) to adjust it to this currency (giving us the pre-tax price)
        $value_excl     = bcmul($value_src, $currencyinfo['cambio']);   
        // Calculate the tax, by multiplying the adjusted price with the taxrate (`impuesto`*0.01 to adjust for it being a percentage)
        $tax            = bcmul($value_excl, bcmul('0.01', $currencyinfo['impuesto']));
        // Add the tax to the price to get the "price including tax"
        $value_incl     = bcadd($value_excl, $tax);
        // Decide which of the values you want to display (including or excluding tax)
        $value          = $value_incl;
        // Decide what we want to add before/after the numeric part of the price (the html-encoded version of the currency symbol)
        $label_prefix   = htmlentities( $currencyinfo['currency_symbol'] . ' ');
        $label_suffix   = ''; // or: htmlentities( ' ' . $currencyinfo['moneda']);
        // Change the number into human readable form
        $label          = number_format((float) $value, $currencyinfo['decimals'], $currencyinfo['decimal_separator'], $currencyinfo['thousands_separator']);
        // Convert that into html
        $label          = htmlentities($label);
        // Define some CSS classes to allow for styling
        $classes_prefix = 'p';
        $classes_number = 'v';
        $classes_suffix = 's';
        $classes_full   = 'price';
        // Now assemble all the pieces
        $html_prefix    = sprintf('<span class="%s">%s</span>',     htmlentities($classes_prefix),  $label_prefix);
        $html_number    = sprintf('<span class="%s">%s</span>',     htmlentities($classes_number),  $label);
        $html_suffix    = sprintf('<span class="%s">%s</span>',     htmlentities($classes_suffix),  $label_suffix);
        $html_full      = sprintf('<span class="%s">%s%s%s</span>', htmlentities($classes_full),    $html_prefix,  $html_number,  $html_suffix );
        // Done
        return $html_full;
    }
}

这就是它的要点。

您可以使用每个 PriceLocalization 方法上可用的 $style 参数将任意信息传递给 displayPriceAs。根据该信息,您可以更改该函数组装其输出的方式。例如,您可以检查 $style['include_tax'] 是否设置为 true/false,如果是,则进行相应调整:

$value = (($style['include_tax'] ?? true) ? $value_incl : $value_excl);

您可以设置价格样式:

.price   { background-color: #EEE; }
.price.p { color: red;   font-weight: bold; }
.price.v { color: green; font-family: courier; }
.price.s { color: blue;  font-weight: bold; }

您还可以使用上面的 $style 参数来引入额外的 classes(在特定情况下)。


可能还值得在您的应用程序中设置 bcscale(15);,以确保以不会导致部分硬币丢失的方式完成数学运算。


ps:根据您的 code/datamodel 调整代码后尚未对其进行测试,因此可能我在某处打错了字。