microtime(true) 是默认首选,因其精度达微秒、无扩展依赖、启动开销近乎零且 PHP 5.1+ 全支持;字符串模式易出错,hrtime(true) 纳秒级精度仅 PHP 7.3+ 支持且属过度精确。

直接用 microtime(true) 就够了,95% 的场景下不需要更复杂的方案。 它返回浮点数,能直接做减法,精度到微秒,启动开销几乎为零,且 PHP 5.1+ 全版本支持。别一上来就配 Xdebug 或折腾 hrtime() —— 除非你真在测纳秒级算法或调试时钟漂移问题。
为什么 microtime(true) 是默认首选
它不是“将就”,而是权衡后的最优解:精度足够(微秒)、无扩展依赖、不干扰执行流、结果可直接参与计算。字符串模式(microtime() 不带参数)必须手动 explode() 和转换,容易出错;而 hrtime(true) 虽然精度更高(纳秒),但只在 PHP 7.3+ 可用,且返回的是纳秒整数,需除以 1e9 才转成秒,对多数 Web 场景属于过度精确。
常见错误现象:
- 用
microtime()(无参数)后直接减,得到字符串拼接结果,比如"0.123456 1716830000" - "0.654321 1716830001"→0 - 在 CLI 脚本里混用
$_SERVER['REQUEST_TIME_FLOAT'],但它在非 Web SAPI(如php script.php)中不存在,会触发 notice
microtime(true) 的正确埋点位置
关键不是“怎么写”,而是“在哪写”——起始和结束点必须包裹真实业务逻辑,排除无关耗时。
立即学习“PHP免费学习笔记(深入)”;
- Web 请求总耗时:放在框架中间件的
handle()开头和return $next($request)之后,不要放在控制器方法里(漏掉路由、中间件、响应组装等环节) - 数据库查询耗时:在
$pdo->query()或 ORM 执行方法调用前后,而不是在 SQL 字符串拼接之后 - 避免在循环体内反复调用
microtime(true)测单次迭代 —— 函数调用本身有开销(约 0.5–1μs),会污染数据;应测整个循环,或改用getrusage()看 CPU 时间 - 如果脚本含
sleep()或阻塞 I/O(如fsockopen),microtime()测的是 wall-clock time(墙钟时间),不是 CPU 占用,此时getrusage()的ru_utime.tv_sec更反映真实计算负载
什么时候该换别的方法
不是 microtime(true) 不好,而是需求变了。
- 要区分用户态 / 内核态 CPU 时间 → 用
getrusage(),比如判断是算法慢还是系统调用多 - PHP 版本 ≥ 7.3 且需要规避 NTP 调时影响(如金融系统计时)→ 改用
hrtime(true),它基于单调时钟,不受系统时间回拨干扰 - 要查每个函数谁最慢、调用栈深度、I/O 等待占比 → 必须上
Xdebugprofiler 或Blackfire,microtime()手动埋点无法覆盖自动加载、析构、异常处理等隐式路径 - 生产环境持续监控 → 别自己写日志打点,用
Prometheus + php-fpm_exporter或 APM 工具,避免日志 IO 成为新瓶颈
真正容易被忽略的点是:同一段代码在不同 SAPI 下,microtime(true) 的起点意义完全不同。CLI 脚本从第一行开始计,而 Web 请求实际应从 SAPI 接收完 HTTP 头那一刻算起 —— 这就是为什么框架中间件里的计时,比在 index.php 开头写 $start = microtime(true) 更真实。别让计时点漂移,毁掉所有优化依据。



















