PHP 8 严格类型是强制执行本机函数的吗?

PHP 8 strict type is forced on native function?

提问人:Matrix 提问时间:2/28/2022 最后编辑:DharmanMatrix 更新时间:5/21/2023 访问量:5767

问:

我的代码适用于 PHP 7:

round(microtime(),3);

但在 PHP 8 中:

致命错误:未捕获的 TypeError:round():参数 #1 ($num) 必须是 int|float 类型,字符串在 [...] 中给出[...]:4 堆栈跟踪:#0 [...]...: round('0.21066100 1646...', 3) #1 {main} 扔进去 [...][...]4号线

如果我强制施法:

round((float)microtime(),3);

它有效,但PHP的所有力量都是自动转换和非严格类型!如果必须编辑我所有数十亿行代码中的所有本机函数以强制强制转换到任何地方,我如何使用 PHP 8?

有没有办法在内部函数上保留自动类型转换?

我在代码中以 microtime() 为例,但是:

round("200 42"); 

作为同样的问题,所以解决方案不仅仅是,这不是这里的话题。microtime(true)

问题是,如果我在我的代码中使用本机函数,则存在潜在的错误并且我无法知道它(错误仅在脚本运行时发生),因此,如果我让 PHP 8 运行,可能会,我的网站的某些页面无法正常工作,我不可能知道它!这是一个大问题!

https://www.php.net/manual/en/migration80.other-changes.php

数学函数 abs()、ceil()、floor() 和 round() 现在正确 注意strict_types指令。以前,他们胁迫了第一个 即使在严格类型模式下也是如此。

因此,此函数必须专注于更新代码,而不是所有本机函数!

类型 转换 php-8

评论

3赞 Álvaro González 2/28/2022
microtime()返回类似 .你很可能想要."0.00369800 1644622698"microtime(true)
1赞 Markus AO 2/28/2022
round("200");将起作用,因为字符串可以强制转换为 int/float 类型。然而,类似的东西是模棱两可的。而且你确实想在模棱两可的类型转换曾经有效的地方更新你的代码......因为它会引起各种异常,随着时间的推移,追踪这些异常所需的时间将比更新代码所需的时间更长。"200""200 42"
1赞 Álvaro González 2/28/2022
“PHP 的所有力量都是自动转换和非严格类型” - 数学函数,例如,如果您启用严格类型 (.这在 PHP/8 中发生了变化round()declare(strict_types=1);
2赞 Álvaro González 2/28/2022
刚刚看到您关于 .在这种情况下,你要舍入的东西不是一个数字,不仅仅是作为类型,而是在逻辑意义上。PHP一直在强化一些以前没有多大意义的行为。总的来说,我认为你对此无能为力。round("200 42");
1赞 Álvaro González 2/28/2022
@Matrix PHP开发人员时不时地修复一些一开始就没有任何意义的语言行为。你可以得到一个对象并得到或者是 .你的代码依赖于一些可疑的行为,这是不幸的,但说PHP开发人员在修复它时是错误的,这是不公平的。如果语言最初没有行为不端,你就不会得到这样的代码。count()DateTime1'abc' == 0true

答:

4赞 Markus AO 2/28/2022 #1

除非声明,否则无需强制转换以匹配所有位置的本机函数签名。您确实需要确保输入到这些函数中的变量可以明确地类型转换为预期的数据类型。我们有一个数学函数的例子,你真的希望有一个有效的数字作为参数,而不管数据类型如何:strict_types

php > echo round("200");
200

php > echo round("200 12");
Warning: Uncaught TypeError: round(): 
Argument #1 ($num) must be of type int|float, string given

在这里,字符串起作用,因为它是一个明确的数字。但是,不会,因为它是模棱两可的。假设你投射它:"200""200 12"

php > echo (int) "200 12";
200

你变成了.这是你所期望的吗?再:"200 12"(int) 200

php > echo (float) "gummy bears";
0

php > echo 200 + "1";
201

php > echo 200 - "gummy bears" + "1";
Warning: Uncaught TypeError: Unsupported operand types: int - string

这些是早期版本的PHP中会通过的异常评估,我们现在得到的是一种祝福。变量只能无损地进行类型转换,“鲁莽”的类型转换和损坏的数据一直是无数规避错误的根源。TypeError

另请参阅: PHP 数字字符串手册 ...具体来说,关于什么可以解释为数字,什么不能解释为数字的部分。基本上,如果你的变量通过了 is_numeric(),那么它对于数学运算来说是可以的——如果没有,你应该得到一个错误消息!以下是手册中的示例列表:

$foo = 1 + "10.5";                // $foo is float (11.5)
$foo = 1 + "-1.3e3";              // $foo is float (-1299)
$foo = 1 + "bob-1.3e3";           // TypeError as of PHP 8.0.0, $foo is integer (1) previously
$foo = 1 + "bob3";                // TypeError as of PHP 8.0.0, $foo is integer (1) previously
$foo = 1 + "10 Small Pigs";       // $foo is integer (11) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
$foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
$foo = "10.0 pigs " + 1;          // $foo is float (11) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
$foo = "10.0 pigs " + 1.0;        // $foo is float (11) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously

总之,你确实想在模棱两可的类型转换曾经有效的地方更新你的代码......从长远来看,与追查“自动转换”时损坏的变量值导致的异常相比,更新代码所花费的时间更少。

评论

0赞 Matrix 2/28/2022
你想象一下,如果每个原生函数的每次调用都是一个可能的未来错误?我不会重新测试我的所有代码,问题不是特定于“round()”,而是 PHP8,因为自动转换已被删除......
1赞 Matrix 2/28/2022
好的,自动转换仅针对 round() floor() ceil() 和 abs() 被删除,因此可以知道哪里有错误: php.net/manual/en/migration80.other-changes.php
2赞 Markus AO 2/28/2022
@Matrix 类型转换/类型杂耍在 PHP 8 中尚未删除。如上所述,工作正常。只有当您尝试使用非数字字符串进行数学运算时,才会出现类型错误,并且您确实希望显示错误,如果参数无效,则会导致无意义的计算。round("200")
0赞 Álvaro González 2/28/2022
@Matrix 该文本意味着这些函数现在在 下按预期工作,我认为您没有使用它。PHP 不再做的是愉快地生成不合逻辑或违反直觉的类型转换,例如 .strict_types=1(int)'gummy bears'
0赞 Will B. 3/1/2022
@Matrix防止将来出现问题的一种常见解决方案是实现涵盖整个代码库的单元测试,并针对各种版本的 PHP 对其进行测试。允许您在将环境迁移到较新版本的 PHP 之前自动测试代码并捕获错误和意外行为。例如,当升级到 7.2.19 时,导致 DatePeriod 抛出 PHP 7.2.18 中没有的异常。
2赞 Cyril c. 2/23/2023 #2

in_array同样的问题:

$a = null;
in_array( 1, $a ); // works in php 7 -null becomes [], fails in php 8
in_array( 1, (array)$a ); // works in php 8 but we don't want to type this... autocast is what made PHP attractive in the first place.

评论

0赞 Matrix 2/24/2023
我还没有测试,但是 mybe 覆盖了强制施法的本机函数......我发现了这一点:stackoverflow.com/questions/15230883/......
0赞 Markus AO 8/15/2023
这又是一个你真正想要错误的情况。这不是如何实现的问题,如果你做了一个数组查找,但不确保你正在处理一个数组,那就是你的代码有问题。用于有条件地计算和明智地处理变量由于某种原因不是数组的情况。如果某个内容不是数组,但您的代码需要一个数组,则意味着在该代码之前有一个异常,您应该注意该异常。if(is_array($a)) { ... }
0赞 Markus AO 8/15/2023
如果您合理地期望 array 或 null 是唯一的两个选项,则可以使用 null 合并运算符来提供默认的空数组来代替构造。在某些特定情况下,我会这样做,如果变量为 null 而不是数组,则循环根本不会迭代——而不是将循环包装在条件中。in_array(1, $a ?? [])if/elseforeach($a ?? [] as $val)if(!is_null($a)) { ... }