PHP 类型是什么

类型是什么?

最近有很多关于PHP类型的讨论。有一些关于如何清理PHP api使之更简单的建议。它们中的大多数都涉及到在一个非常基础的级别上更改PHP的类型设计系统。所以我认为谈论这个是一个好主意。类型是什么?


通常来说的类型系统
一般类型系统中的通常有4个主属性。或者,实际上,他们可以用两种方式来判断:强制和明确。

“明确”描述了这些类型在编译时是否可解析。因此,明确类型系统要么要求您指定每种类型(通常称为“严格”类型),要么使用类型推断来推断类型。虽然不同,但都是明确类型的。没有明确类型,您就有了动态类型。这是编译器在编译时无法知道所有类型信息,某些类型的信息必须在运行时才能确定。

“强制”描述了当你试图改变一种类型时发生的事情。你能轻易改变变量类型吗?在强类型语言中,一旦一个变量被定义为一个特定类型(通过显式或运行时类型),它就永远不会改变类型。在弱类型语言中,变量可以在程序的过程中改变它们的类型。
看看一些流行的语言
语言 明确性 强制
PHP Static(静态) + Dynamic(动态) Weak(弱类型)
Python Dynamic(动态) Strong(强类型)
C Static(静态) Strong(强类型)
Java Static(静态) Strong(强类型)
JavaScript Dynamic(动态) Weak(弱类型)
Ruby Dynamic(动态) Weak(弱类型)


根据定义,所有的静态语言都将是强类型的。但在这里面甚至有等级。例如,在C中,如果您将一个整数传递给一个期望浮点数的函数,它会很高兴地为您(只要它不是一个指针)进行转换。但是在Java中,同样的功能将会是一个编译错误。
注意,JavaScript和PHP都是动态的和弱的。但也要注意,PHP也是静态的。静态和弱?我只是说从定义上这是不可能的,但现实就是这样,这是很奇怪的。


结果是,我们得到了静态类型的一些不错的部分,没有任何好处。静态分析PHP仍然是非常困难的。
那么,让我们来权衡一下子类型系统。

权衡
权衡是相当有趣的。一方面,如果一种语言是静态类型和强类型的,那么在不运行程序的情况下进行分析就容易得多。我们称这种分析为“静态”分析。因为它只关注代码,而不是运行时信息。
因此,静态和强类型语言更容易分析。这对我们有什么影响?它让我们有一些编译器可以自动检查某些类型的错误。您可以检测您想要字符串,但是得到了一个数组。或者你期望一个整数,但是传递了一个字符串。等等。这意味着所有类型转换将被显式地指定。


这并不意味着没有bug。这只是意味着没有类型的bug。这是一个非常重要的区别,例如:
function foo(int length_in_feet){…}
int length_in_meters = 10;
foo(length_in_meters);
从类型的角度来看,这是100%有效的代码。没有任何静态分析会告诉你这是错误的。但这段显然是错误的(因为foo 函数需要的是 以英尺表示的程度,而调用的函数传递的参数却是以米表示的长度)。
当我们从静态到动态类型(同时保持强类型)时,发生了一件有趣的事情。一旦我们知道了类型(通过显式转换或其他操作),我们就可以依赖它。这意味着编译更容易一些。当然,我们也不能静态分析,但是对于程序员工作就更容易。因为你知道一旦变量被创建,它的类型就不会改变,它比弱语言更容易处理。

但是你有什么损失吗?嗯,是的。你失去灵活性。你失去了包容的属性。
有了静态类型的语言,如果类型不匹配,就由您来修复它。对于小型系统来说,这很容易做到。对于大型系统,开发人员对系统有很深入的了解,这是很容易做到的。但对于初级开发人员来说,这可能是困难的。对于一个新的程序员来说,它可能会让人感到困惑。
在编写自定义代码时,这并不是什么大问题。这种类型的安全是非常有益的。
但是想象一下,你正在用一种纯静态类型的语言运行WordPress。你安装了一个插件,突然你就会在类型不匹配上得到一个编译器错误。这可能是个问题!但如何解决呢?对于刚开始编程的人?这是办不到的…
这取决于所涉及的类型。
对于一些不匹配来说,这是一种烦恼。“期待int类型,但发现浮点类型”。当然,明确表示很好,但这很烦人。当看起来是理智的时候为什么不能做理智的处理呢?
最终,这是PHP的类型系统的基础。试着去做理智的事情,如果你做不到,就会犯错。


PHP的类型系统

PHP有两个半独立的类型系统。它有一个对象类型系统,一个其他不是对象类型系统(是的,您可以在数组和可调用函数上明确类型,但是它们本身是复杂的)。
对于对象,它遵循一个严格的 + 弱模型。这很奇怪,因为类型检查只发生在函数边界或instanceof() 函数上。例如:
function foo(Bar$Bar) 
{$Bar=10;}
我们严格了Bar类型,但是变量改变了类型。这意味着,当我们分析PHP时,我们需要记住,类型可以在一行上进行更改。因此,谈论变量的类型更多的是讨论如何通过一个程序进行类型传播。
除了对象之外,我们还有一个完全弱的系统。如果不考虑奇怪的资源类型,PHP将始终尝试为您进行合理的转换。例子:
function foo($a) {
    return $a + 1;
}

当我们调用这个函数时,我们不知道结果会是什么。但是我们可以确定它将是一个数值类型(浮点型或整数型)。现在,有趣的是当我们传入非数值的东西时会发生什么。如果$a是字符串呢?如果它是一个数组呢?一个布尔呢?
PHP将使用您使用类型的上下文来确定它应该是什么类型(重新读取该行,这很重要,我们将再次回到这一点)。
当我们传入一个字符串时,它会说"嘿,这是一个数值运算,我们试着把它转换成数值"然后它会看着字符串,然后说“这看起来像个数字吗?”如果是这样,那么它就会悄悄地将它转换成那个数字,然后继续进行。如果没有,它将发出一个通知 notice 错误,并返回最接近的值(0)。
我们称这是杂耍(juggling)判断类型机制。PHP的类型系统是基于它的。
在很多情况下,这是非常有价值的。它使应用程序更加灵活,但实际上它更加宽容。“你想要一个浮点数,但试着传递一个整数,没问题,我们会使程序成功。”
魔鬼总在边缘案例中。PHP以它们而闻名。但总的来说,只要你还在甜蜜期,它就能很好地工作。

上下文决定一切
PHP的整个标量类型系统是围绕上下文构建的。当您将一个变量传递给strlen()时,不管类型是什么,您都说您想要一个字符串长度。
PHP的整个类型系统是围绕这个事实构建的。您需要上下文来确定类型应该是什么。

多态性
多态性基本上是颠倒了上下文的关系。它不提供上下文的调用代码,而是让类型本身提供上下文。所以当你调用$foo->bar()时,你会说“我不管$foo是什么,只要在它做一个 bar() 调用”。
通过多态性,功能可以简单地通过更改类型来进行更改。因此,相同的方法可以在两个不同的对象上做两件不同的事情($duck->quack()可以“鸭子嘎嘎叫(quack)”或者做一些更邪恶的事情,但是对于调用代码,它只是一个quack() 函数)。
这是非常强大的,因为它颠覆了正常的上下文关系。它不是提供上下文的调用,而是让被调用的东西确定上下文。

那么,当多态性遇到PHP的弱类型系统时会发生什么呢?


混乱
想象一下,我们有关于标量类型的方法。下面的代码会做什么:
$foo->length();
这能计算字符串长度吗?它是否计算数组长度?它能计算其他的东西吗?
从表面上看,这似乎是一个没有意义的问题。毕竟,这就是多态的意义所在。
但是如果你想要得到字符串长度,会发生什么呢?那么如果它是一个实现__toString的对象会发生什么呢?您期望方法调用失败吗?或者你认为__toString 函数会先被调用?
好吧,这没什么大不了的。如果你想要一个字符串长度,你只需要确保你有一个字符串!
$str =(string)$foo;
$str->length();
或者更好的是,如果我们有严格的标量类型声明:
function my_strlen(string $str){
  return $str->length();
}
我们很有可预见性。我们有理智!我们知道我们的代码在字符串上工作,所以我们知道长度方法是有效的!太棒了!
但是如何调用代码呢?如果你想要安全,你几乎只能用强制转换:
my_strlen((string)$foo)
但现在我们又回到了起点。我们已经失去了强制类型的所有好处。这是相同类型的杂耍机制,但是这次我们把杂耍的要求推到我们的代码的调用者上。奇怪。
强制转换至少是我们所能做的安全修改。至少,如果转换没有意义(比如将“apple”传递给期望一个整数的函数),那么至少隐含的基于上下文的转换将会引起错误(或注意)。显式的转换意味着您可以隐藏bug。

安全的强制转换

目前有一项建议将安全的转换添加到PHP中。这基本上是一系列的函数,这些函数会在理智的情况下进行转换。因此,它提供了与底层PHP需求相同的上下文,也允许程序员在调用时确定上下文。my_strlen(to_string($foo));这就好多了,因为一个不安全的值会导致错误。如果严格的标量类型声明(提示)会发生,一个安全的类型转换机制会使它更安全。


我的结论

我认为如果没有标量类型声明(类型提示),您就不能合理地使用标量方法。没有它,上下文就丢失了。

我认为如果没有一个安全的强制机制,就不能进行标量类型声明。否则你只是在改变隐藏错误的地方。
而且您肯定不能删除上下文相关的api(现有的过程api),除非从根本上改变整个类型系统。在这一点上,它不再是PHP了。
因此,选择(对于标量方法API)可以归结为:不要这样做,或者提供两个API(一个过程,一个通过方法)。

这听起来很可怕。


文章来自 Anthony  https://blog.ircmaxell.com/2014/10/whats-in-type.html



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值