PHP中的价格精度处理

价格的精度处理在程序中至关重要,在WooCommerce中就有一连串的函数对价格进行精度操作。我提取出来是这样的,可以在任何程序中使用:

<?php
// 消毒
function sanitize_text( $str, $keep_newlines = false ) {
if ( is_object( $str ) || is_array( $str ) ) {
return '';
}
$filtered = (string) $str;
if ( stripos($filtered, '<') !== false) {
$filtered = str_replace( '<', '<', $filtered );
$filtered = preg_replace( '@<(script|style)[^>]*?>.*?</\1>@si', '', $filtered );
$filtered = strip_tags( $filtered );
$filtered = str_replace( "<\n", "<\n", $filtered );
}
if ( ! $keep_newlines ) {
$filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered );
}
$filtered = trim( $filtered );
// Remove percent-encoded characters.
$found = false;
while ( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match ) ) {
$filtered = str_replace( $match[0], '', $filtered );
$found = true;
}
if ( $found ) {
// Strip out the whitespace that may now exist after removing percent-encoded characters.
$filtered = trim( preg_replace( '/ +/', ' ', $filtered ) );
}
return $filtered;
}
function get_price_decimals(){//小数点位数
return 0;
}
function get_price_decimal_separator(){//小数点分割符
return '.';
}
function get_rounding_precision() {// 精度+2,最小值为6
$precision = get_price_decimals() + 2;
if ( $precision < absint( 6 ) ) {
$precision = absint( 6 );
}
return $precision;
}
function price_format_decimal( $number, $dp = false, $trim_zeros = false ) {// 价格格式化
$number = $number ?? '';
$locale = localeconv();
$decimals = array( get_price_decimal_separator(), $locale['decimal_point'], $locale['mon_decimal_point'] );
// Remove locale from string.
if ( ! is_float( $number ) ) {
$number = str_replace( $decimals, '.', $number );
// Convert multiple dots to just one.
$number = preg_replace( '/\.(?![^.]+$)|[^0-9.-]/', '', sanitize_text($number) );
}
if ( false !== $dp ) {
$dp = intval( '' === $dp ? get_price_decimals() : $dp );
$number = number_format( floatval( $number ), $dp, '.', '' );
} elseif ( is_float( $number ) ) {
// DP is false - don't use number format, just return a string using whatever is given. Remove scientific notation using sprintf.
$number = str_replace( $decimals, '.', sprintf( '%.' . get_rounding_precision() . 'f', $number ) );
// We already had a float, so trailing zeros are not needed.
$trim_zeros = true;
}
if ( $trim_zeros && strstr( $number, '.' ) ) {
$number = rtrim( rtrim( $number, '0' ), '.' );
}
return $number;
}
<?php
// 消毒
function sanitize_text( $str, $keep_newlines = false ) {
  if ( is_object( $str ) || is_array( $str ) ) {
    return '';
  }

  $filtered = (string) $str;
  if ( stripos($filtered, '<') !== false) {
    $filtered = str_replace( '<', '<', $filtered );
    $filtered = preg_replace( '@<(script|style)[^>]*?>.*?</\1>@si', '', $filtered );
    $filtered = strip_tags( $filtered );
    $filtered = str_replace( "<\n", "<\n", $filtered );
  }

  if ( ! $keep_newlines ) {
    $filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered );
  }
  $filtered = trim( $filtered );

  // Remove percent-encoded characters.
  $found = false;
  while ( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match ) ) {
    $filtered = str_replace( $match[0], '', $filtered );
    $found    = true;
  }

  if ( $found ) {
    // Strip out the whitespace that may now exist after removing percent-encoded characters.
    $filtered = trim( preg_replace( '/ +/', ' ', $filtered ) );
  }

  return $filtered;
}



function get_price_decimals(){//小数点位数
    return 0;
}

function get_price_decimal_separator(){//小数点分割符
    return '.';
}

function get_rounding_precision() {// 精度+2,最小值为6
  $precision = get_price_decimals() + 2;
  if ( $precision < absint( 6 ) ) {
    $precision = absint( 6 );
  }
  return $precision;
}

function price_format_decimal( $number, $dp = false, $trim_zeros = false ) {// 价格格式化
  $number = $number ?? '';

  $locale   = localeconv();
  $decimals = array( get_price_decimal_separator(), $locale['decimal_point'], $locale['mon_decimal_point'] );

  // Remove locale from string.
  if ( ! is_float( $number ) ) {
    $number = str_replace( $decimals, '.', $number );

    // Convert multiple dots to just one.
    $number = preg_replace( '/\.(?![^.]+$)|[^0-9.-]/', '', sanitize_text($number) );
  }

  if ( false !== $dp ) {
    $dp     = intval( '' === $dp ? get_price_decimals() : $dp );
    $number = number_format( floatval( $number ), $dp, '.', '' );
  } elseif ( is_float( $number ) ) {
    // DP is false - don't use number format, just return a string using whatever is given. Remove scientific notation using sprintf.
    $number = str_replace( $decimals, '.', sprintf( '%.' . get_rounding_precision() . 'f', $number ) );
    // We already had a float, so trailing zeros are not needed.
    $trim_zeros = true;
  }

  if ( $trim_zeros && strstr( $number, '.' ) ) {
    $number = rtrim( rtrim( $number, '0' ), '.' );
  }
  return $number;
}
<?php // 消毒 function sanitize_text( $str, $keep_newlines = false ) { if ( is_object( $str ) || is_array( $str ) ) { return ''; } $filtered = (string) $str; if ( stripos($filtered, '<') !== false) { $filtered = str_replace( '<', '&lt;', $filtered ); $filtered = preg_replace( '@<(script|style)[^>]*?>.*?</\1>@si', '', $filtered ); $filtered = strip_tags( $filtered ); $filtered = str_replace( "<\n", "&lt;\n", $filtered ); } if ( ! $keep_newlines ) { $filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered ); } $filtered = trim( $filtered ); // Remove percent-encoded characters. $found = false; while ( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match ) ) { $filtered = str_replace( $match[0], '', $filtered ); $found = true; } if ( $found ) { // Strip out the whitespace that may now exist after removing percent-encoded characters. $filtered = trim( preg_replace( '/ +/', ' ', $filtered ) ); } return $filtered; } function get_price_decimals(){//小数点位数 return 0; } function get_price_decimal_separator(){//小数点分割符 return '.'; } function get_rounding_precision() {// 精度+2,最小值为6 $precision = get_price_decimals() + 2; if ( $precision < absint( 6 ) ) { $precision = absint( 6 ); } return $precision; } function price_format_decimal( $number, $dp = false, $trim_zeros = false ) {// 价格格式化 $number = $number ?? ''; $locale = localeconv(); $decimals = array( get_price_decimal_separator(), $locale['decimal_point'], $locale['mon_decimal_point'] ); // Remove locale from string. if ( ! is_float( $number ) ) { $number = str_replace( $decimals, '.', $number ); // Convert multiple dots to just one. $number = preg_replace( '/\.(?![^.]+$)|[^0-9.-]/', '', sanitize_text($number) ); } if ( false !== $dp ) { $dp = intval( '' === $dp ? get_price_decimals() : $dp ); $number = number_format( floatval( $number ), $dp, '.', '' ); } elseif ( is_float( $number ) ) { // DP is false - don't use number format, just return a string using whatever is given. Remove scientific notation using sprintf. $number = str_replace( $decimals, '.', sprintf( '%.' . get_rounding_precision() . 'f', $number ) ); // We already had a float, so trailing zeros are not needed. $trim_zeros = true; } if ( $trim_zeros && strstr( $number, '.' ) ) { $number = rtrim( rtrim( $number, '0' ), '.' ); } return $number; }

使用也很简单:

$number = 3.59;
$decimal_places = get_price_decimals();
$formatted_number = price_format_decimal( $number, $decimal_places );
$number = 2.948;
$decimal_places = 2;
$formatted_number = price_format_decimal( $number, $decimal_places );
$number = 3.59;
$decimal_places = get_price_decimals();
$formatted_number = price_format_decimal( $number, $decimal_places );

$number = 2.948;
$decimal_places = 2;
$formatted_number = price_format_decimal( $number, $decimal_places );
$number = 3.59; $decimal_places = get_price_decimals(); $formatted_number = price_format_decimal( $number, $decimal_places ); $number = 2.948; $decimal_places = 2; $formatted_number = price_format_decimal( $number, $decimal_places );

而根据我查阅资料,最终得出两种处理精度的方式:

$number = 3.59;
$decimal_places = 2;
$number_format = number_format( floatval( $number ), $decimal_places, '.', '' );
$round = round($number*pow(10, $decimal_places))/pow(10, $decimal_places);
$number = 3.59;
$decimal_places = 2;
$number_format = number_format( floatval( $number ), $decimal_places, '.', '' );
$round = round($number*pow(10, $decimal_places))/pow(10, $decimal_places);
$number = 3.59; $decimal_places = 2; $number_format = number_format( floatval( $number ), $decimal_places, '.', '' ); $round = round($number*pow(10, $decimal_places))/pow(10, $decimal_places);

最终WooCommerce中的计算函数、与另外两个计算结果一模一样。需要注意的是number_format出的精度只是显示是处理了,但是不会改变其值,与原值比较是一样的,而经过round处理的值会是一个新值,有时候可以搭配起来使用,比如数据库中存在的是6位小数,而只给用户看两位,就可以配合起来使用了。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
Nobody can go back and start a new beginning, but anyone can start today and make a new ending.
没有人可以回到过去从头再来,但是每个人都可以从今天开始,创造一个全新的结局
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容