本文最初揭橥于 PHPArch 网站 ,经原作者 Chris Tankersley 授权,InfoQ 中文站翻译并分享。

PHP 至少是一门有趣的编程措辞
这门措辞和用它构建的程序常日属于两种设计哲学。
在这里,我所说的并非软件开拓生命周期,如瀑布或敏捷,而是关于软件该当是什么样的基本思想。
这些思想被称为“精确的办法”(The Right Way)和 “更糟便是更好”(Worse is better)。

PHP 又是一门相称奇怪的编程措辞。
当人们抱怨这门措辞“很槽糕”时,他们并没有说错。
这门措辞确实有很多不好的地方。
搁在以前,这门措辞还有更多糟糕的问题。
嘲笑 PHP 的博文《全面解析 PHP 的槽糕设计》(PHP: a fractal of bad design)确实有几个精确的不雅观点,纵然这些不雅观点在九年前揭橥时就已经由时了。

php演讲PHP 是最糟糕的编程说话 PHP

然而,与此同时,开拓职员却可以利用 PHP 创建构造上“精确”的软件,并从其他措辞中引入被视为良好实践的哲学。
像 Laminas 和 Symfony 这样的框架就利用了面向工具编程的最佳实践,使开拓者可以用这些框架编写构造精确的代码

PHP 是怎么做到这些的?这是由于 PHP 是最糟糕的编程措辞。

设计软件

1991 年,Richard P. Gabriel 揭橥了一篇文章《Lisp:好,坏,如何赢得大》(Lisp: Good News, Bad News, How to Win Big)。
这篇文章的论点是,在软件设计和寿命方面,“更糟便是更好”的哲学将是更好的选择。
他之以是得出这一结论,是由于他意识到涌现了两种不同的程序设计流派,他分别将之命名为“麻省理工学院/斯坦福风格”(MIT/Standford Style),或者“精确的办法”,以及“新泽西风格”(New Jersey Style)或者“更糟便是更好”。

这两种哲学的目标相似,但在关键领域却有所不同。
两种风格都侧重于哲学理念的四个关键领域:大略性(Simplicity)、精确性(Correctness)、同等性(Consistency)和完全性(Completeness)。

麻省理工学院风格是这样描述的:

大略性:设计一定要大略,不论它的实现还是接口,都一定要大略。
相较而言,让接口保持大略更主要。
精确性:在所有可以不雅观察到的方方面面,设计一定要精确。
不要企图做一个禁绝确的设计。
同等性: 设计一定不能是不一致的。
为了确保同等性,你可以略微捐躯大略性和完全性。
同等性和精确性同等主要。
完全性:设计一定要尽可能多地涵盖主要的情形。
所有符合预期的情形一定要被覆盖到。
完全性优先级该当高于大略性。

至于新泽西风格,Gabriel 说,它将其目标定义为:

大略性:设计一定要大略,不论它的实现还是接口,都一定要大略。
而相较而言,让实现保持大略更主要。
大略是最主要的,其他的特性都不如保持大略更主要。
精确性:在所有可以不雅观察到的方面,设计一定要精确。
但是可以为了大略而轻微捐躯精确性。
同等性:设计一定不能太过不一致。
某些情形下,为了担保大略可以捐躯同等性。
如果将某个不常见的情形引入设计,会导致实现变繁芜或者不一致,那么就不要考虑这种情形。
完全性:设计一定要尽可能多地涵盖主要的情形。
所有符合预期的情形一定要被覆盖到。
完全性可以为任何其他特性让步。
实际上,一旦威胁到实现的大略性,完全性必须要被捐躯。
如果为了保持大略,可以捐躯同等性来实现完全性;尤其是接口的同等性。

这场辩论的关键是用 LISP 和 C 作为例子来解释为什么“更糟便是更好”。
对付 LISP 程序员 Gabriel 来说,LISP 是一种比 C 更好的措辞,速率和 C 一样快,而且 Common LISP 的设计、开拓和标准化已经花了很多年。
定义该措辞的规范吸取了所有不同的 LISP 的精华,而当代开拓环境对付 LISP 开拓者来说是最好的。

LISP 是精确的办法

LISP 代表了软件开拓的“精确的办法”。
LISP 易于交互,你可以通过各种办法与它交互。
希望从 Fortran 中调用 LISP?你可以从 Fortran 中调用 LISP 并将数据传入,反之亦然。
在利用遗留代码时,你可以愉快地利用 LISP 的所有当代“豪华”特性。

LISP 拥有同等的设计,这得益于它的规范。
如果你研究一下 Python 这样的当代措辞,规范在供应多个后端和编译器方面有很大的浸染,而且它们都以同样的办法阐明或编译代码。
这些工具是一流的,1991 年的 LISP 拥有我们本日仍旧享受的所有舒适,比如步骤调试、数据检讨和花哨的编辑器。

作为一种措辞,LISP 是完备的。
它具有前辈的面向工具编程层、多重继续、一流的工具以及函数和类型。
LISP 彷佛是开拓职员心中想要的编程措辞。

1991 年,LISP 这么编程措辞可能处于有史以来的最佳状态。
这种技能上的精确性并没有被实际利用所证明。
LISP 的开拓商正在衰退。
多年来负面新闻和缺点定位阻碍了 LISP 的外部荣誉。
人们不再将其视为向终极用户交付软件的办法。

就开拓而言,LISP 每每代表着许多与“大规模预先设计”(Big Design Up Front,BDUF)一样的空想。
如果你曾经利用过瀑布模型(Waterfall Model)这样的设计方法,你就会创造一些问题。
“精确的办法”非常强调同等性、精确性,并确保考虑到所有能想到的问题。

LISP 本身并非一种单一的措辞,而是一个措辞家族。
只管 Common LISP 被设计成一种标准,但是 LISP 本身的实现办法是根据须要完成的各种事情而存在的。
Lockless Inc 网站上的一篇文章指出,这种“碎片化”是 LISP 终极失落败的决定成分之一。
只管 LISP 坚持软件设计的“精确的办法”,但是这种碎片化导致代码掩护和可移植性都受到了影响。

C 和 Unix 是缺点的办法

同时,由于 Unix 的涌现,C 措辞逐渐成为软件开拓的首选方法。
C 措辞是为 Unix 设计的,而 Unix 是用 C 措辞设计的。
它的开拓职员与麻省理工学院的 LISP 及其作者有着不同的设计态度。

在 1972 年,C 措辞被设计成一种大略的措辞。
到 1991 年,它已经发生了一些变革,但是 C 措辞的基本事理没有改变。
一些特性是为了知足开拓者和 Unix 的需求而添加的。
由于措辞很大略,以是编写编译器和程序很随意马虎。
只管这种措辞并不会妨碍你进行繁芜的编程,但是与 LISP 比较,C 措辞估计只有程序员所需的 50-80% 特性。

但是, C 措辞却有很强的可移植性。
相对付常用于 LISP 软件和环境的硬件,它也可以运行在低功率硬件上。
这一成分使得它可以在更广泛的机器上编译和运行软件。
C 措辞和 Unix 很随意马虎利用,Gabriel 认为 Unix 和 C 措辞会像病毒一样盛行起来。

在 Dennis Ritchie 设计和构建 Unix 的过程中,C 措辞得到了发展。
由于贝尔实验室(Bell Labs)不被许可正式进入打算机领域,以是 Unix 也可以轻松地分发给各种不同的用户。
这些用户帮助修补 Unix 以知足他们自己的需求。
Dennis Ritchie 能够根据需求将这些补丁整合在一起,而不必事先考虑这些需求。

与 LISP 不同,C 至今仍旧被大量利用。
只管高等的阐明性措辞,如 PHP、JavaScript 和 Python 是许多开拓者的首选,但是这些高等措辞很多都是用 C 措辞开拓的。
纵然像 Rust 这样的竞争对手开始崭露锋芒,但能够在小型低功率设备上运行仍旧是 C 措辞的上风。

PHP 是最槽糕的

因此,“更糟便是更好”的软件首先会被接管,其次它会利用户期望更少,第三,这些软件将被不断改进,直到靠近“精确的方法”的程度。

——Richard Gabrie

在这一启迪的几年后,Rasmus Lerdorf 开始研究个人主页/表单阐明器,也便是我们现在所知的 PHP。
PHP/FI 的出身是由于 Lerdorf 须要掩护他的主页,并与表单和数据库进行交互。
PHP/FI 乃至不是作为一种实际的编程措辞设计的,而是作为 C 措辞之上的一层脚本和函数设计的。

PHP 很大略

设计一定要大略,不论是它的实现还是接口。

PHP 底层利用了 C 措辞,我们之前已经说过,这部分是“最糟糕的”。
然而,这也带来了一些上风,最主要的是,更大略的底层措辞可以让它更随意马虎扩展。
虽然 Hack/HHVM 采取了更多的 C++ 方法,但 PHP 本身仍旧是 C 措辞。

只需短短几个小时就能学完这门措辞的内部构造。
Elizabeth Smith 揭橥过一篇关于 PHP 扩展的精彩演讲,个中先容了大量关于 PHP 的内部事情事理。
这门措辞本身借鉴了其他 C 风格的措辞,不仅易于阅读,并且能够跟 C 风格的其他措辞相互转换。

PHP 的大多数接口,或者说标准库,都非常大略,由于大多数核心功能都只不过是包装了各种 C 措辞库,然后险些原封不动地公开出来。
只管这样做会导致接口上的一些不一致,但是它为来自 C 或 C++ 的开拓者供应了一个熟习的环境。

PHP 措辞非常看重于 Web 开拓。
将 HTTP 中的观点提取出来并在措辞中找到相似的观点常日非常大略。
希望理解一个要求的头信息吗?get_headers() 就能知足你。
获取要求信息就像读取 $_GET 和 $_POST 全局变量一样大略。

PHP 保持了大略的开拓者接口,并且尽可能地保持内部构造的大略。

PHP(险些)是精确的

在所有可以不雅观察到的方面,设计一定要精确。
但是可以为了大略性而轻微捐躯精确性。

在这里,PHP 方向于选择“大略”而不是精确。
在 HHVM 涌现之前,措辞的外不雅观和特性一贯没有得到规范。
Zend 阐明器本身便是规范,并且这门措辞的行为办法总是 “精确”的(不包括实际的缺点)。
要想用别的东西代替 PHP 引擎,就必须实现现有引擎的所有特性。

许多核心函数的 LAX 函数参数和返回类型都使得系统的事情更随意马虎。
像 strpos() 这样的函数返回值可以是整型数或布尔值,相对付严格设计成返回整型数或抛出非常的方法,处理要轻微随意马虎一些。

看 PHP 措辞的发展,险些所有新特性都是建立在开拓职员须要的根本上,而不是“由于它错了以是必须修复”的严明想法。
更多地关注那些严格类型和非常缺点是一种更精确的干事方法。
然而,还有一些东西,比如简短的箭头函数(arrow function)、属性和列举,才是开拓者想要用来简化代码的东西。

PHP 不须要同等性

设计一定不能太过不一致。
某些情形下,为了保持大略可以捐躯同等性。

我乃至不打算假装 PHP 是同等的,但是它的同等性已经足够了。
当涉及到数组与字符串函数时,人们可能会抱怨 needle/haystack 参数顺序。
不过,一样平常而言,数组函数是同等的,而字符串函数也是同等的。
与底层 C 库保持同等比在措辞中保持同等要大略得多。

PHP 在其他方面也足够同等。
正如我在 strpos() 中提到的,PHP 对付碰着缺点的函数每每会相称同等地返回 FALSE。
这未必是精确的,但它却是同等的。
带下划线和不带下划线的函数名常日都会匹配其根本库。

为了大略起见, PHP 措辞捐躯了同等性,但是纵然没有这个规范,它仍旧努力在故意义的地方保持同等。

PHP 的完全性符合所需

设计一定要尽可能多地涵盖主要的情形。

无论何时,在针对 PHP 需求最大的设计任务:编写 Web 运用程序时,PHP 都是完备的。
PHP 从未被设计成一种可以适用于编程天下所有问题的措辞。
只管如此,它的大略性还是使它可以用于 Web 以外的场合。
PHP 最初的目的便是为 Web 编程供应最基本的功能,这一趋势一贯持续至今。

修正核心措辞常日是由开拓职员的需求驱动。
全体社区提出修正见地,然后经由社区投票,决定新特性被谢绝、改变或者接管。
该措辞的许多创新都源于快速完成事情的须要。
即便我们接管了其它措辞的功能,也是由于它使我们的开拓变得大略,而很少是由于其他措辞做得“更精确”。

本日,你可以用 PHP 开拓 Web 运用程序。
五年后,你仍旧可以用 PHP 开拓 Web 运用程序,只不过会增加一些新特性。
但是,措辞本身的完全性已经符合本日所需。
如果未来有须要,我们可以随时修正措辞或为它添加新功能。

更糟便是更好吗?

Gabriel 承认,“更糟便是更好”的哲学指的是设计看起来很糟糕,大概不应该作为更好的选择。
唯一的问题是,当他核阅这两种哲学时,与麻省理工学院/“精确的办法”的设计哲学比较,“更糟便是更好”终极仍旧是更灵巧的选择,“具有更好的生存特性”。
如果我们看一下 PHP,就可以证明“更糟便是更好”这一不雅观点。

这些年来,Gabriel 承认他在哪种办法更好之间摇摆不定。
PHP 社区一贯在辩论我们是该当精确地干事还是连续大略地干事。
我们有像 Laminas 这样的框架,以经典的打算机科学办法构建库,然后我们有像 Laravel 这样的框架,关注开拓者的体验和速率。
PHP 本身二者兼具。

下次再听到有人骂 PHP 的时候,就随他喷去吧。
这门措辞确实很糟糕。
但从许多方面来看,PHP 的龟龄和广泛利用证明了这样一个事实:用“精确的办法”干事并不总是比用“最糟糕”的办法干事好。
当有人吐槽你正在利用的框架时,你要明白从长远来看这并不主要。
选择一种你认为适宜自己的设计哲学,并欣然接管这一点:更糟的可能实际上更好。

作者先容:

Chris Tankersley 拥有多种角色:丈夫、父亲、作家、演讲家、播客主持人和 PHP 开拓者。
Chris 在 12 年的编程生涯中利用 了很多种不同的框架和措辞,但是他一天的大部分韶光都在利用 PHP 和 Python。
他是《Docker for Developers(尚无中文版)的作者,并与公司和开拓者互助,将容器整合到他们的事情流中。

原文链接:

https://www.phparch.com/2021/09/education-station-php-is-the-worst/