然而这些问题通常被过分强调了(我们有集成开发环境),很难否定状况还是相当好的。还应当指出的是,许多函数表现出的问题远远超过了诡异的名字这个问题。通常边缘情况的行为是没有被完全考虑的,因而有了在调用代码中对它们进行特殊处理的需要。(对字符串函数来说,边缘情况通常包括空字符串或者超出字符串范围的偏移量。)
一个一般的建议是在PHP6中实现巨大数量的别名,用来统一函数名称和参数顺序。因此我们将会有string\pos(),string\reoplace(),string\complement_span()或者类似的。个人而言(而且这看起来像是对许多php-src开发者的意见)这些对我的意义很小。现在的这些函数名已经深深的根植在PHP程序员的记忆中了,对它们实现一些不重要的装饰性的改变看起来好像不值得。
原生类型面向对象API的引入另一方面也提供了一个API重新设计的契机(原文:The introduction of an OO API for primitive types on the other hand offers an opportunity of an API redesign as a side effect of switching to a new paradigm)。这也是真正让我们从零开始,不需要考虑旧的API的期望输出。两个例子:
咋一看,哪个是arraay_map和array_filter各自的使用?(原文:what are array_map and array_filter applied to? )他们调用的顺序是什么?变量$input隐藏在两个闭包之间,函数的书写顺序也和他们实际调用的顺序相反。现在同样的例子使用面向对象的语法:
多态
目前PHP有提供Contable接口,这个接口可以通过类实现自定义的输出函数count($obj)。为什么需要这个?因为我们PHP的函数没有多态。然而我们方法中确实需要多态:
如果数组实现$array->count()作为一个方法,实际上代码是不会在意$array是不是一个数组的,他可以是其他任何类型的实现count()方法的对象,这基本上给了我们Countable的所有行为,~(原文:This basically gives us the same behavior as Countable, just without the engine hackery it requires.)
这也是一个很一般的解决方案。举个例子,你可以实现一个实现所有字符串类型方法的UnicodeString类,然后可以随便的使用正常的字符串和UnicodeStrings。好吧,至少这还是理论。这很明显局限于那些字符串方法的使用,而且调用级联操作的时候会返回错误(原文:This would obviously only work as long as the usage is limited to just the string methods, and would fail once the concatenation operator is employed)(运算符重载目前只支持内核中的类)。
我仍然有强大的信念希望这个清晰起来,同样应用在数组等上面。通过继承相同的接口,你可有一个和数组行为方式相同的SplFixedArray。(原文:you could have an SplFixedArray behave the same way as an array, by implementing the same interface.)
既然我们已经总结了这个方法的一些好处,让我们也来看看它的问题:
松散的类型
摘抄自Anthony发表的博客:
标量不是对象,但更重要的是他们不是任何类型。PHP依赖一个类型系统,字符串和数字是同一个。系统中许多的灵活性基于任何标量可以很容易的转换为其他标量。
更重要的是,由于松散的类型系统,你不可能在任何时候知道一个变量的类型是哪个。你可以说出你想要他是什么类型,但你不知道他内在的类型是什么。Even with casting or scalar type hinting it isn’t a perfect situation since there are cases where types can still change.
现在我们弄明白了,是的,我们确实想将数字视为字符串。对我来说,这样来处理想这样使用这种技术的地方是可以接受的。
对于数组情况就更简单了:他不会出现讲一个数组操作视为一个其他不是数组类型的操作。
另一方面可以通过标量类型提示改善这个问题(我完全认为在PHP所有的版本都存在——最令人尴尬的问题是现在仍然没有(原文:which I totally assume to be present in any PHP version this gets in - really embarrassing that we still don’t have them))。如果内类型提示string,你获取输入的字符串将会是一个字符串(即使传递给函数的不是——这取决于类型提示实现的具体内容)。
当然了,我并不是暗示这里没有一点问题。由于错误的函数设计,有时候可能会发生未知的类型潜入代码中,例如substr($str, strlen($str))将自作聪明的返回bool(false)而不是string(0) ""。(不过,这个问题仅有substr存在。面向对象的API不存在那个问题,所以你碰不到那个问题。)
function change($arg) { echo $arg->length();//$arg looks like object
$arg[0] = 'x';//但是没有对象的传递语义
}
$str = 'foo';
change($str);//$str stays the same
$array = ['foo', 'o', 'o'];
change($array);//$array stays the same
我们当然将会改变传递语义。首先,在我看来通过值传递来传递像数组这种大的数据结构是一个相当low的想法,我更愿意他们像对象一样传递。然而,那将是一个相当大的突破性的向后兼容,并且那将不易于自动的重构(原文:However, that would be a pretty big backwards-compatibility break and one that’s not easy to refactor automatically)(至少我猜想是这样的。我没有做实验去探索这样一个改变带来的实际影响)。另一方面,对于字符串通过对象方式传递参数将是一个灾难,除非我们让字符串同一时间完全的不可变,放弃目前所有的局部变量的可变性(我个人发现非常的容易——去尝试改变一个Python字符串的一个字节)。
我不知道是否有好的方法去解决这个预期的问题,除了在我们的文档中强调字符串和数组在面向对象的方法中仅仅视作”伪对像“,不是真正的对象。
这个问题可以被扩展到其他的对象相关的特性。例如你可将会问像$string instanceof string这样的是否正确。我还没有确定整个事情的完整走向。也许严格坚持仅仅在面向对象的方法使用,然后强调他们不是真正的对象会好一点。然而也许支持面向对象系统的更深层次的特性也会好点。这个观点应该进一步的思考下。