[PHP源码阅读]number_format函数
上次讲到PHP是如何解析大整数的,一笔带过了number_format的处理,再详细阅读该函数的源码,以下是小分析。
函数原型
string number_format ( float $number [, int $decimals = 0 ] )
string number_format ( float $number , int $decimals = 0 , string $dec_point = "." , string $thousands_sep = "," )
函数可以接受1、2、4个参数(具体可以看代码的实现)。
如果只提供第一个参数,number的小数部分会被去掉,并且每个千位分隔符都是英文小写逗号"," ;
如果提供两个参数,number将保留小数点后的位数到你设定的值,其余同楼上;
如果提供了四个参数,number 将保留decimals个长度的小数部分, 小数点被替换为dec_point,千位分隔符替换为thousands_sep
PHP_FUNCTION(number_format)
// number
// 你要格式化的数字
// num_decimal_places
// 要保留的小数位数
// dec_separator
// 指定小数点显示的字符
// thousands_separator
// 指定千位分隔符显示的字符
/* {{{ proto string number_format(float number [, int num_decimal_places [, string dec_separator, string thousands_separator]])
Formats a number with grouped thousands */
PHP_FUNCTION(number_format)
{
// 期望number_format的第一个参数num是double类型的,在词法阶段已经对字面量常量做了转换
double num;
zend_long dec = 0;
char *thousand_sep = NULL, *dec_point = NULL;
char thousand_sep_chr = ',', dec_point_chr = '.';
size_t thousand_sep_len = 0, dec_point_len = 0;
// 解析参数
ZEND_PARSE_PARAMETERS_START(1, 4)
Z_PARAM_DOUBLE(num)// 拿到double类型的num
Z_PARAM_OPTIONAL
Z_PARAM_LONG(dec)
Z_PARAM_STRING_EX(dec_point, dec_point_len, 1, 0)
Z_PARAM_STRING_EX(thousand_sep, thousand_sep_len, 1, 0)
ZEND_PARSE_PARAMETERS_END();
switch(ZEND_NUM_ARGS()) {
case 1:
RETURN_STR(_php_math_number_format(num, 0, dec_point_chr, thousand_sep_chr));
break;
case 2:
RETURN_STR(_php_math_number_format(num, (int)dec, dec_point_chr, thousand_sep_chr));
break;
case 4:
if (dec_point == NULL) {
dec_point = &dec_point_chr;
dec_point_len = 1;
}
if (thousand_sep == NULL) {
thousand_sep = &thousand_sep_chr;
thousand_sep_len = 1;
}
// _php_math_number_format_ex
// 真正处理的函数,在本文件第1107行
RETVAL_STR(_php_math_number_format_ex(num, (int)dec,
dec_point, dec_point_len, thousand_sep, thousand_sep_len));
break;
default:
WRONG_PARAM_COUNT;
}
}
/* }}} */
代码执行流程图

_php_math_number_format_ex
函数实现的各种参数数量,最终都会调用_php_math_number_format_ex函数。函数主要做的是:
处理负数;
根据要保留的小数点对浮点数进行四舍五入;
调用strpprintf函数将浮点数表达式转成字符串表示;
计算需要分配给结果变量的字符串长度;
将结果拷贝到返回值中(如果有千位符,则进行千位符分割)
strpprintf
这个函数是实现浮点数与字符串的转换,如上文所说,最终是调用了php_conv_fp函数做的转换(这里是通过gdb调试做的定位),而php_conv_fp函数,往下追踪,调用的是zend_dtoa函数,
更多细节注解,见github项目提交记录。
总结
阅读完这个函数的源码,学习到的是浮动数与字符串的互相转换的实现细节,字符串与浮点数之间的关系较复杂,之后还要继续学习。
原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
更多精彩内容,请关注个人公众号。

[PHP源码阅读]number_format函数的更多相关文章
- [Redis源码阅读]sds字符串实现
初衷 从开始工作就开始使用Redis,也有一段时间了,但都只是停留在使用阶段,没有往更深的角度探索,每次想读源码都止步在阅读书籍上,因为看完书很快又忘了,这次逼自己先读代码.因为个人觉得写作需要阅读文 ...
- [Redis源码阅读]dict字典的实现
dict的用途 dict是一种用于保存键值对的抽象数据结构,在redis中使用非常广泛,比如数据库.哈希结构的底层. 当执行下面这个命令: > set msg "hello" ...
- [Redis源码阅读]redis持久化
作为web开发的一员,相信大家的面试经历里少不了会遇到这个问题:redis是怎么做持久化的? 不急着给出答案,先停下来思考一下,然后再看看下面的介绍.希望看了这边文章后,你能够回答这个问题. 为什么需 ...
- linux源码阅读笔记 fork函数
在阅读源码的过程中,发现找不到fork函数的定义.后来在linux/init/main.c中找到了这样一条语句 static inline _syscall0(int,fork) 原来这里就是fork ...
- linux源码阅读笔记 asm函数
在linux源码中经常遇到__asm__函数.它其实是函数asm的宏定义 #define __asm__ asm,asm函数让系统执行汇编语句. __asm__常常与__volatile__一起出现. ...
- [PHP源码阅读]explode和implode函数
explode和implode函数主要用作字符串和数组间转换的操作,比如获取一段参数后根据某个字符分割字符串,或者将一个数组的结果使用一个字符合并成一个字符串输出.在PHP中经常会用到这两个函数,因此 ...
- CI框架源码阅读笔记3 全局函数Common.php
从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...
- 3 EventTime 事件时间类和TimeNow函数——Live555源码阅读(一)基本组件类
这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 这里是时间相关类的第三个部分,也是最后一个部分. EventTime 事件时间类 这个类和Dela ...
- PHP源码阅读笔记一(explode和implode函数分析)
PHP源码阅读笔记一一.explode和implode函数array explode ( string separator, string string [, int limit] )此函数返回由字符 ...
随机推荐
- centos7破解mariadb密码
第一步,停止运行mysql: systemctl stop mariadb.service 第二步,使用" -skip-grant-tables"参数重新启动mysql: mysq ...
- c#中的interface abstract与virtual介绍
abstract 与virtual : 方法重写时都使用 override 关键字,interface中的方法和abstract方法都要求实现 interface用来声明接口1.只提供一些方法规约, ...
- vue.js移动端app实战3:从一个购物车入门vuex
什么是vuex? 官方的解释是:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 简单来说就 ...
- sql unique约束详解
UNIQUE 约束唯一标识数据库表中的每条记录. UNIQUE 和 PRIMARY KEY 约束均为列或列集合提供了唯一性的保证. PRIMARY KEY 拥有自动定义的 UNIQUE 约束. 请注意 ...
- 手把手封装数据层之DataUtil数据库操作的封装
上一篇我们写完了数据库连接的封装 没有看的请移步上一篇关于数据库连接的内容 这次我们讲数据库操作的封装.数据库的操作就是增删改查:心再大一点就可以直接分为查询和其他. 因为查询是有返回对象的,而其他都 ...
- 排序算法——选择排序(js语言实现)
选择排序:顾名思义选择,选择排序属于O(N^2)的排序算法,意思就是选择数组中的最小的拿出来放在第一位,然后再剩下的数里面,选择最小的,排在第二位,以此类推. 例如:8 3 4 5 6 2 ...
- 为什么Java字符串是不可变对象?
转自 http://developer.51cto.com/art/201503/468905.htm 本文主要来介绍一下Java中的不可变对象,以及Java中String类的不可变性,那么为什么Ja ...
- sed修炼系列(一):花拳绣腿之入门篇
本文为花拳绣腿招式入门篇,主要目的是入门,为看懂sed修炼系列(二):武功心法做准备.虽然是入门篇,只介绍了基本工作机制以及一些选项和命令,但其中仍然包括了很多sed的工作机制细节.对比网上各sed相 ...
- 获取ip地址及城市信息
大家好,今天给大家分享的是一个简单的知识获取登录用户的ip地址及城市信息,lz是一个小白,如果有哪些错误的地方 欢迎大家指出 东西很简单,直接上代码 [HttpPost] public string ...
- jdk不同版本对String拼接的优化分析
1. 测试demo代码 测试循环中字符串拼接优化 public class ForTest { public static void main(String[] args) { String a = ...