为什么PHP不允许“传统”的类型提示?

8

刚刚发现在PHP中允许使用type-hinting,但不适用于整数、字符串、布尔和浮点数。

为什么PHP不允许对整数、字符串等类型进行类型提示?


@close-because-its-subjective: 我本来想将这个标记为维基页面,但现在我无法这样做了。"Suppose" 是一个主观的词语,但 PHP 开发人员之所以这样做是有明确原因的,如果有人知道这个原因,就可以给出明确的答案。 - mpen
与此相关:http://stackoverflow.com/q/29169252/3933332 - Rizier123
3个回答

10

自 PHP 7.0 版本开始,支持 boolintfloatstring 类型。这项支持是在 标量类型 RFC 中添加的。有两种模式: 弱类型和严格类型。我建议阅读该 RFC 以充分理解它们之间的差异,但基本上只有在弱类型模式下才会发生类型转换。

给定以下代码:

function mul2(int $x) {
    return $x * 2;
}
mul2("1");

在弱类型模式下(也是默认模式),这将把"1"转换为1

要启用严格类型,请在文件顶部添加declare(strict_types=1);。在严格模式下,将发出以下错误:

Fatal error: Argument 1 passed to mul2() must be of the type integer, string given


我曾认为这个RFC因某些原因被拒绝了。很高兴看到它通过了! - mpen

9

PHP是一种松散类型的语言,在使用上下文中,您的“基本”类型会自动进行type-juggled。使用类型提示也不会改变这一点,因为字符串可以被用作整数,反之亦然。类型提示只对数组和对象等复杂类型有帮助,因为它们不能像整数、字符串或其他基本类型那样清晰地转换。

换句话说,由于PHP没有特定类型的概念,因此您无法要求在某个地方使用int,因为它不知道int到底是什么。另一方面,一个对象确实是某种类型,因为MyClass不能与MyOtherClass互换。


仅供参考,以下是尝试在这些类型之间进行转换时会发生的情况(不是详尽列表):

转换为对象 (ref)
"如果将一个对象转换为对象,则不会修改它。如果将任何其他类型的值转换为对象,则会创建一个内置类stdClass的新实例。如果该值为NULL,则新实例将为空。数组将转换为具有按键命名的属性和相应值的对象。对于任何其他值,成员变量scalar将包含该值。"

对象转换为int / float (ref)
未定义的行为

对象转换为布尔值 (ref)
在PHP5中始终为TRUE

对象转字符串 (参考)
如果适用,将调用对象的 __toString()魔术方法

对象转数组 (参考)
"如果将对象转换为数组,则结果是一个数组,其元素是对象的属性。键是成员变量名称,有一些值得注意的例外情况:整数属性无法访问;私有变量在变量名前面加上类名;受保护的变量在变量名前加上 '*'。这些前缀值两侧有空字节。这可能会导致一些意外的行为。"

数组转整数/浮点数 (参考)
未定义的行为

数组转布尔值 (ref)
如果数组为空(即没有元素),则将其评估为FALSE--否则,评估为TRUE。

数组转字符串 (ref)
字符串“Array”;使用print_r()var_dump()打印数组的内容。

数组转对象 (ref)
“数组转换为一个具有由键命名的属性和相应值的对象。”


好的,但这不是原始类型提示的论据吗?如果对象不能像整数一样被操纵,我们至少应该有一个非对象的类型提示吧? - mpen
2
嗯,我不能反驳这一点。没有人说PHP的系统是完美的。 :-) 就我个人而言,通常更喜欢语言是强类型的。 - Wiseguy
我也是这样想的...但有时我们不得不用PHP编写代码 ;) - mpen

1

称之为“类型提示”并不正确。 “提示”意味着它是一种可选的类型,只是一个提示而非要求,但是带有类型的函数参数根本不是可选的 - 如果您输入错误的类型,您会收到致命错误。称之为“类型提示”是一个错误。

现在来看看为什么 PHP 中没有函数参数的原始类型。PHP 没有基本类型之间的障碍 - 即字符串、整数、浮点数、布尔值 - 或多或少可以互换,您可以使用 $a = "1"; 然后使用 echo $a+3; 得到 4。所有内部函数也都是这样工作的 - 如果函数期望一个字符串,而你传递一个整数,它会转换成字符串。如果函数期望一个浮点数,并得到一个整数,它被转换为浮点数等等。这与对象类型不同 - 例如,SimpleXMLElementDirectoryIterator 之间没有转换 - 也不能有,这毫无意义。

因此,如果您引入一个接受整数1而不是字符串1的函数,则会在内部函数和用户函数之间创建不兼容性,并为假定它们几乎相同的任何代码创建问题。这将是PHP程序行为上的重大变化,需要通过使用此类函数的所有代码传播此更改-否则,在“严格”和“非严格”代码之间转换时会出现错误风险。这将意味着需要类型变量、类型属性、类型返回值等-这是一项重大变革。由于PHP不是编译语言,因此您无法获得静态类型控制的好处,但也没有其缺点-您只会遇到不便,而不会增加安全性。这就是为什么PHP不接受参数类型的原因。
另一种选择是强制类型转换,即类似于内部函数所做的行为-在类型之间进行转换。不幸的是,这种方法并不能满足严格类型支持者的要求,因此迄今为止还没有达成共识。
另一方面,对象类型从未引起争议-很明显它们之间没有转换,没有代码假定它们是可互换的,检查只能对它们进行严格检查,这适用于内部和外部函数。因此,引入严格的对象类型并不是问题。

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