本文最初揭橥于 PHPArch 网站 ,经原作者 Chris Tankersley 授权,InfoQ 中文站翻译并分享。
PHP 至少是一门有趣的编程措辞。这门措辞和用它构建的程序常日属于两种设计哲学。在这里,我所说的并非软件开拓生命周期,如瀑布或敏捷,而是关于软件该当是什么样的基本思想。这些思想被称为“精确的办法”(The Right Way)和 “更糟便是更好”(Worse is better)。
PHP 又是一门相称奇怪的编程措辞。当人们抱怨这门措辞“很槽糕”时,他们并没有说错。这门措辞确实有很多不好的地方。搁在以前,这门措辞还有更多糟糕的问题。嘲笑 PHP 的博文《全面解析 PHP 的槽糕设计》(PHP: a fractal of bad design)确实有几个精确的不雅观点,纵然这些不雅观点在九年前揭橥时就已经由时了。
然而,与此同时,开拓职员却可以利用 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/