【问题标题】:Why is "traditional" type-hinting not allowed in PHP?为什么 PHP 中不允许使用“传统”类型提示?
【发布时间】:2011-06-12 20:43:50
【问题描述】:

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

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

【问题讨论】:

  • @close-because-its-subjective:我认为这是一个 wiki,但我不能再这样做了。 “假设”是一个主观词,当然,但 PHP 开发人员这样做是有明确原因的,如果有人知道那是什么,可以给出明确的答案。

标签: php type-hinting


【解决方案1】:

从 PHP 7.0 开始,支持 boolintfloatstring。在scalar types RFC 中添加了支持。有两种模式:弱模式和严格模式。我建议阅读 RFC 以充分理解差异,但本质上类型转换只发生在弱模式下。

鉴于此代码:

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

在弱模式(这是默认模式)下,这会将"1" 转换为1

要启用严格类型,请将declare(strict_types=1); 添加到文件顶部。严格模式下会报错:

致命错误:传递给 mul2() 的参数 1 必须是整数类型,给定字符串

【讨论】:

  • 我认为这个 RFC 由于某种原因被拒绝了。很高兴看到它通过了!
【解决方案2】:

PHP 是松散类型的,您的“原始”类型会根据使用它们的上下文自动成为type-juggled。类型提示不会真正改变这一点,因为字符串 可以 用作 int,反之亦然。类型提示只会对复杂类型(如数组和对象)真正有帮助,因为它们不能清晰地转换为整数、字符串或其他原语。

换一种说法,由于 PHP 没有特定类型的概念,你不能在某处要求 int,因为它不知道 int 到底是什么是。另一方面,对象 的特定类型,因为 MyClass 不能与 MyOtherClass 互换。


仅供参考,当您尝试在此类类型之间进行转换时会发生以下情况(并非详尽列表):

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

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

布尔对象 (ref)
在 PHP5 中,总是 TRUE

对象到字符串 (ref)
如果适用,将调用对象的__toString() magic method

对象到数组 (ref)
“如果将对象转换为数组,则结果是一个数组,其元素是对象的属性。键是成员变量名称,但有一些值得注意的例外:整数属性不可访问;私有变量的类名前面加上“

数组到 int/float (ref)
未定义的行为

数组到布尔值 (ref)
如果数组为空(即没有元素),则计算结果为 FALSE,否则为 TRUE。

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

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

【讨论】:

  • 好的,但这不是 for 原始类型提示的参数吗?如果对象不能作为整数来处理,我们不应该至少有一个非对象的类型提示吗?
  • 好吧,我无法反驳。没有人说 PHP 的系统是完美的。 :-) 我通常更喜欢强类型语言。
  • 我也是...但有时我们必须用 PHP 编写 ;)
【解决方案3】:

称其为“类型提示”是不恰当的。 “提示”意味着它是一些可选的类型,仅仅是提示而不是要求,但是类型化的函数参数根本不是可选的——如果你给它错误的类型,你会得到致命的错误。称其为“类型提示”是错误的。

现在来看看 PHP 中函数参数没有原始类型的原因。 PHP 在基本类型之间没有障碍 - 即字符串、整数、浮点数、布尔值 - 或多或少可以互换,您可以先使用 $a = "1";,然后使用 echo $a+3;,然后再使用 4。所有内部函数也以这种方式工作——如果函数需要一个字符串并且你传递一个整数,它会被转换为字符串,如果函数需要一个浮点数并获得一个整数,它会被转换为浮点数,等等。这与对象类型不同——例如,SimpleXMLElementDirectoryIterator 之间没有转换 - 也不可能,这没有任何意义。

因此,如果您引入接受整数 1 而不是字符串 1 的函数,则会在内部函数和用户函数之间造成不兼容,并为假设它们几乎相同的任何代码带来问题。这将是 PHP 程序行为方式的一个重大变化,并且需要使用这些函数在所有代码中传播这种变化 - 因为否则在“严格”和“非严格”代码之间转换时会出现错误。这意味着类型变量、类型化属性、类型化返回值等的必要性——巨大的变化。而且由于 PHP 不是一种编译语言,因此您不会从静态类型控制中获得好处和它的缺点——您只会带来不便,但不会增加安全性。这就是 PHP 不接受参数类型的原因。

还有另一种选择 - 强制类型,即类似于内部函数所做的行为 - 类型之间的转换。不幸的是,这个不满足严格类型的支持者,因此到目前为止还没有找到共识,因此没有共识。

另一方面,对象类型从来没有争议 - 很明显它们之间没有转换,没有代码假设它们是可互换的,检查只能对它们严格,内部和外部函数都是如此.因此,引入严格的对象类型不是问题。

【讨论】:

    猜你喜欢
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 2018-07-27
    • 1970-01-01
    相关资源
    最近更新 更多