为什么PHP严格类型允许错误类型的函数参数?

4
我正在使用 PHP 7.4.16。我在我的 PHP 文件中启用了 strict_types,以为它会通过抛出 TypeError 来防止将 string 参数传递给期望 int 的函数。然而,该函数实际上接受了 string 并将其强制转换为 int。但是,如果我在函数上放置返回类型提示,则可以按预期工作,抛出 TypeError
这对我来说毫无意义,并且似乎是一个明显的不一致性,会导致错误。是否有人可以解释为什么会这样,或者我是否做错了什么?
测试代码:
<?php
declare(strict_types=1);

$ids = ['1', '2', '3'];

// No error thrown, coerces string argument to int.
array_map(fn (int $id) => $id, $ids);

// Throws PHP Fatal error:  Uncaught TypeError: Return value of {closure}() must be of the type int, string returned
array_map(fn ($id): int => $id, $ids);

1
这个我三年前提出的问题在评论中为您提供了答案。因此,严格类型由调用范围决定,内部代码始终是弱类型,除了call_user_func,它被转换为直接函数调用作为优化。https://3v4l.org/5OGH6 - Rain
1个回答

8

strict_types 只影响声明了该选项的文件内部的函数调用。根据 PHP 文档所述:

注意: 严格类型只应用于启用了严格类型的文件内部进行的函数调用,而不是在该文件中声明的函数。如果没有启用严格类型的文件对在启用了严格类型的文件中定义的函数进行调用,则将尊重调用者的偏好(强制转换类型),并进行强制转换。

对于您的情况,这些示例并未直接调用回调函数本身,而是将其作为参数传递给了 array_map,这意味着无论在何处实现 array_map 函数,当 array_map 调用您的回调时,它都会优先使用强制转换类型。

解决此问题的一个可能方法是封装 array_map 并在已声明 strict_types 的文件中调用您的回调,例如:

<?php
declare(strict_types=1);

$ids = ['1', '2', '3'];

function strict_array_map($fn, $arr){
    return array_map(fn (...$arguments) => $fn(...$arguments), $arr);
}

// Now TypeError is thrown correctly
strict_array_map(fn (int $id) => $id, $ids);

// Throws PHP Fatal error:  Uncaught TypeError: Return value of {closure}() must be of the type int, string returned
strict_array_map(fn ($id): int => $id, $ids);

https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict


2
@Jacob 这里的区别在于你没有直接调用函数本身。你的函数是在 array_map 中被调用的。如果你声明 $callback = fn (int $id) => $id; 并尝试在同一文件中使用 $callback($ids[0]); 调用它,你将会触发 strict_types - Alex Ruiz
1
@Jacob 我理解你的解释,但如果问题是“如何在array_map中实现strict_types?”- 你有什么想法吗? - Dri372
2
@AlexRuiz 应该更新您的答案,并最好附带一个小例子。 - Dri372
1
@AlexRuiz 啊,你关于array_map是调用函数的解释帮助我理解了发生了什么。谢谢! - Jacob
1
@Jacob,你应该考虑在标题中加入array_map,你的问题非常好,它展示了Php如何实现strict_types,我认为array_map的情况可能已经被遗忘或难以实现。 - Dri372
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接