PHP的array、traversable、foreach等的设计失误(一)
《PHP恨你》这个系列停笔好久了,主要是一直没空,然后光吐槽也不产生价值。不过这个我新发掘的case,勉强可算语言设计上学到的一课,所以就写一下吧。
第一件小事是,PHP的typehint不支持union type,如果一个参数可以是多个类型,就只好用注释了,或者更常见的情况——就不写了,读代码的人你自己猜吧。
Traversable这个接口表示的是可以用foreach遍历。而array当然也是可以用foreach的。所以一个函数接受Traversable,没有什么道理不接受array。但是因为上面说的限制,导致你无法标注typehint,如果你标注了Traversable,传一个array进去就报错。这真是个悲伤的故事。
实际上Traversable并不是一个可以直接实现的interface,而是一个“internal engine interface”,也就是说它的用途只有typehint和instanceof。而标typehint的用途因为上述原因变得很鸡肋,也就只剩下instanceof。而instanceof代码也基本上就是
if( !is_array( $items ) && !$items instanceof Traversable )
//Throw exception here
这个罗嗦样子。
其实让这个接口同时覆盖array又有什么问题呢?
注意,有人可能会说普通object其实都能foreach(行为是遍历所有public属性和值),那么Traversable应该可以覆盖所有object,但那样这接口就没意义了。
确实,Traversable接口的真实含义更接近:如果实现了此接口,就代表有定制化的遍历行为。不过遍历一个普通对象是比较少见的(因为PHP中array已经同时具备了关联数组的用途),通常是reflection的用法,而不像Traversable/array是频繁的集合遍历操作。PHP不是一向崇尚“实用主义”嘛,为什么这里不按照实用出发呢?
如果说第一件小事只是稍微带来不便,第二件事就非常蛋疼,且贻害无穷了。
(待续)
没后文了?
第二件事情是 hash 和 array 混用,以及默认 deep equal 的 holy shit 么?