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 分享
No matter what happened in the past, you have to believe that the best is yet to come.
无论过去发生过什么,你都要相信,最好的尚未到来
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

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

    暂无评论内容