PHP 8.1 引入严格类型转换检查,~ 运算符隐式转整型会触发「Implicit conversion from float to int loses precision」警告;应改用 intdiv() 和 % 替代手动位运算模拟整除与取模。
php
8.1 引入严格类型转换检查,`~` 运算符隐式转整型会触发「implicit conversion from float to int loses precision」警告;应改用 `intdiv()` 和 `%` 替代手动位运算模拟整除与取模。
在 PHP 8.1+ 中,对浮点数执行 ~(按位取反)操作会先隐式将其转换为整型(如 ~1.0833333333333333 → ~1),该过程丢弃小数部分且无显式类型声明,因此触发
E_DEPRECATED
级别警告:
Implicit conversion from float 1.0833333333333333 to int loses precision
原代码中使用 ~~($a / $b) 是一种历史惯用写法(利用 ~ 的两次取反实现向零截断),但其本质仍是不安全的隐式转换。PHP 官方已提供语义明确、性能更优的内置替代方案。
✅ 推荐修复方式
1. 替换 div():使用 intdiv()
intdiv() 是 PHP 7.0+ 引入的安全整除函数,要求两参数均为整型,
自动向下取整(向零截断)
,且在 PHP 8.1+ 下完全避免隐式转换警告:
⚠️ 注意:intdiv() 要求 $a 和 $b 均为整型。若原始输入可能为浮点数,请先显式转换并校验:
if (!is_int($a) || !is_int($b)) { throw new TypeError('intdiv() expects integer operands'); }
立即学习
“
PHP免费学习笔记(深入)
”;
2. 替换 mod():使用 % 运算符
PHP 的取模运算符 % 在整型操作数下行为确定(向零取余),且无隐式转换开销:
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
? 补充说明:$a % $b 与 fmod($a, $b) 不同——前者是整型取模(结果符号同被除数),后者是浮点取模。本例中 mod() 原逻辑基于整除结果计算,故 % 完全等价且更高效。
? 应用示例:修复 d2g() 函数
将上述重构后的 div() 和 mod() 应用于日序转公历日期函数:
✅ 所有 div() 和 mod() 调用均通过类型声明和 intdiv/% 消除了警告,同时提升可读性与运行效率。
? 总结
❌ 避免 ~~($a / $b) 等依赖隐式转换的“技巧”,它们在 PHP 8.1+ 已过时且危险;
✅ 优先使用 intdiv($a, $b) 实现整除,语义清晰、类型安全、无警告;
✅ 使用 $a % $b 替代手写取模逻辑,简洁高效;
✅ 在方法签名中添加 int 类型声明,配合静态分析工具(如 PHPStan)提前捕获类型错误;
? 若需处理浮点数除法并截断,应显式调用 (int)floor($a / $b) 或 (int)trunc($a / $b) 并注释意图,而非依赖 ~。
遵循以上实践,即可彻底消除 PHP 8.1 的精度丢失警告,并使代码更健壮、可维护。
/**
* 安全整除:等价于 (int)($a / $b),但要求整型输入、无精度警告
* @param int $a
* @param int $b
* @return int
*/
public static function div(int $a, int $b): int
{
return intdiv($a, $b);
}/**
* 安全取模:等价于 $a % $b(整型上下文)
* @param int $a
* @param int $b
* @return int
*/
public static function mod(int $a, int $b): int
{
return $a % $b;
}public static function d2g(int $jdn): array
{
$j = 4 * $jdn + 139361631;
$j += self::div(self::div(4 * $jdn + 183187720, 146097) * 3, 4) * 4 - 3908;
$i = self::div(self::mod($j, 1461), 4) * 5 + 308;
$gd = self::div(self::mod($i, 153), 5) + 1;
$gm = self::mod(self::div($i, 153), 12) + 1;
$gy = self::div($j, 1461) - 100100 + self::div(8 - $gm, 6);
return [$gy, $gm, $gd];
}