作者 | Oscar Merida
PHP是一门有趣的编程语言。语言与利用语言构建的程序通常属于两种设计理念。这里我指的不是瀑布式或敏捷之类的软件开发生命周期,而是软件管理的基本思想。有人将这些思想称为“正确的方式”以及“Worse is Better”。
PHP包含一些奇怪的问题,很多人由于这些问题而贬低这门语言,但他们也没有错。这门语言有很多问题。有人嘲笑PHP糟糕的设计,还提出了一些正确的观点,尽管这些观点是九年前提出的,但它们依然是正确的。
然而,开发人员却可以利用PHP创建结构“正确”的软件,而且还引入了其他公认好评的实践。你可能接触过Laminas和Symfony之类的框架,它们拥有最佳面向对象编程实践,开发人员可以利用这些框架编写结构正确的代码。
为什么会这样?因为PHP是最糟糕的编程语言。
1. 设计软件
1991年,Richard P. Gabriel发表了一篇题为《Lisp: Good News,Bad News, How to Win Big”》的论文。该论文的论点是,对于软件的设计和寿命,“Worse is Better”,也就是说越糟越好。他之所以得出这样的观点,是因为他意识到程序设计出现了两种截然不同的流派,他称之为“MIT/Standford Style”(学院派)和“The Right Way”(正确的方式,又称新泽西风格,即后来的Worse is Better)。
这两种理念的目标相似,但对关键领域的看法不同。两种风格都侧重于四大关键思想领域:简单性、正确性、一致性和完整性。
学院派的风格描述为:
- 简单性:设计必须简单,无论是实现还是接口。接口的简单性比实现的简单性更重要。
- 正确性:所有可观察方面的设计必须都是正确的。绝对不允许错误。
- 一致性:设计不能出现不一致。为了避免不一致,允许设计稍微削弱简单性和完整性。一致性与正确性同样重要。
- 完整性:设计必须尽可能涵盖重要情况。必须涵盖所有合理预期的情况。不允许简单性过度降低完整性。
至于新泽西风格,Gabriel认为的目标是:
- 简单性:设计必须简单,无论是实现还是接口。实现的简单性比接口的简单性更重要。简单性是设计中最重要的考虑因素。
- 正确性:所有可观察方面的设计必须都是正确的。但是简单性比正确性略微重要一点。
- 一致性:设计不能过于不一致。在某些情况下,为了简单性,可以牺牲一致性。尽管如此,为了避免引入实现的复杂性或不一致,最好放弃设计中不太常见的情况。
- 完整性:设计必须尽可能涵盖重要情况。必须涵盖所有合理预期的情况。但是为了其他目标,可以牺牲完整性。事实上,一旦危及实现的简单性,就必须牺牲完整性。如果可以保持简单性,则可以牺牲一致性来实现完整性,接口的一致性尤其没有价值。
争论的关键是以LISP和C为例,讨论为什么越糟越好。Gabriel 是一名 LISP 程序员,他认为LISP比C更好。LISP 不仅和C一样快,而且Common LISP花费了数年时间进行设计、开发和标准化。定义语言的规范充分利用了各种不同版本的LISP的优点,而且LISP是最好的现代开发环境之一。
2. LISP 是正确的方式
LISP代表了软件开发的“正确方式”。LISP易于交互,你可以通过各种方式与之交互。想通过Fortran调用 LISP?你可以通过Fortran调用LISP并传入输入数据,反之亦然。在处理遗留代码时,你可以奢侈地享受 LISP 的所有现代特性。
LISP的规范保证了设计的一致性。看一看Python之类的现代语言就会发现,规范对于提供多个后端和编译器提供了很大帮助,所有解释或编译代码的方式都相同。LISP的工具是一流的,1991年的LISP就拥有我们至今仍在享受的各种“福利”,比如逐步调试、数据检查和精美的编辑器。
作为一种语言,LISP是完备的。它具有先进的面向对象编程层、多重继承、一流的对象以及函数和类型。LISP似乎是开发人员心中所想的编程语言。
1991年是LISP这门编程语言的最佳时期。这种技术上的正确性并不是由实际使用来证实的。LISP的开发正在走下坡路。多年的负面新闻和定位失误影响了 LISP 的外部声誉,不再被视为向最终用户提供软件的一种方式。
在开发方面,LISP提倡的很多思想与“预先做大量的设计”不谋而合。如果你曾使用过诸如瀑布模型之类的设计方法,就能看出一些问题。“正确的方式”非常强调一致性、正确性,并确保考虑到所有可以想到的问题。
LISP本身也不止一种语言,它有一个语言家族。虽然 Common LISP是标准,但 LISP 本身也可用于实现各种基本的功能。Lockless Inc网站上的一篇文章认为,这种分化是LISP最终失败的决定性原因之一。即使LISP坚持软件设计的“正确方式”,但这种分化导致代码维护和可移植性均受到了影响。
3. C 和 Unix 是错误的方式
与此同时,多亏了Unix,C成为了开发软件的首选语言。C是为Unix设计的,而 Unix是从C设计出来的。C的开发人员采取的设计方式与LISP不同。
1972年,C还是一门非常简单的编程语言。到1991年,C发生了一些变化,但基本原理没有改变。功能都是根据开发人员的需要和 Unix 的需要添加的。编写编译器和程序很容易,因为语言本身非常简单。虽然你也可以利用C编写复杂的程序,但与LISP相比,估计C只拥有程序员想要的50%~80%的功能。
然而,C的便携性非常惊人。与通常用于LISP软件和环境的硬件相比,C还可以在能力有限的硬件上运行。因此,C能够在更广泛的机器上编译和运行软件。C 软件和Unix非常容易运行,Gabriel认为Unix和C会像病毒一样流传开来。
C的开发始于 Dennis Ritchie 设计和构建Unix时。由于贝尔实验室不被允许正式进入计算机领域,因此 Unix 很容易分发给其他的各种用户。这些用户为了满足自己的需求给Unix打补丁。Dennis Ritchie能够根据需要合并这些补丁,而不必提前想好这些需求。
与LISP不同,C至今仍被广泛使用。虽然PHP、JavaScript和Python等高级语言和解释性语言是许多开发人员的首选,但许多高级语言都是用C开发的。尽管如今出现了像Rust这样的竞争对手,但在小型低功率设备上运行仍然是C的优势。
4. PHP最糟糕
首先,越糟越好的软件会被接受;其次,用户的期望更低;第三,这些软件可以被改进,直到接近“正确”的程度。
—— Richard Gabriel
几年后,Rasmus Lerdorf开始致力于创建个人主页/表单解释器(Personal Home Page/Forms Interpreter),即我们现在所说的PHP。PHP/FI的诞生是因为Lerdorf 需要维护他的主页,并与表单和数据库进行交互。PHP/FI的设计甚至称不上编程语言,而是作为C之上的脚本和函数层。
5. PHP 很简单
设计必须简单,无论是实现还是接口。
实际上,PHP底部使用了C语言,我们认为这是“最糟糕的”。然而,这带来了一些优势,最重要的是,简单的底层语言更加方便扩展。虽然 Hack/HHVM 采用了更多的C++方法,但PHP本身仍然是C语言。
你可以在短短几个小时内学习 PHP 语言的内部结构。Elizabeth Smith 曾发表过一个关于 PHP 扩展的精彩演讲(https://www.slideshare.net/auroraeosrose),其中介绍了大量关于 PHP 的内部工作原理。PHP借鉴了其他C风格的语言,不仅方便阅读,而且还可以切换成C风格系列的其他语言。
PHP的大部分接口或标准库都很简单,因为大部分核心功能只不过是对各种C库进行了包装,然后原封不动地公开了。虽然这会导致接口的不一致,但也为C或C++开发人员提供了一个熟悉的环境。
PHP语言主要用于Web开发。你可以很容易地从该语言中找到某个HTTP的概念。想要获取请求的标头?可以直接使用get_headers()。想要获取请求信息?只需读取全局变量$_GET 和 $_POST。
PHP的接口很简单,而且内部结构也非常简单。
6. PHP(几乎)是正确的
所有可观察方面的设计必须都是正确的。简单性比正确性更好。
此处,在简单性与正确性的选择中,PHP更倾向于“简单”。在HHVM出现之前,并没有任何关于PHP的外观或功能的规范。Zend解释器本身就是规范,而且该语言的行为方式始终是“正确的”(不包括实际的 bug)。如果你想替换掉PHP 引擎,则需要实现该引擎的所有怪癖。
许多核心函数的参数和返回类型都不是特别严格,主要目的是让系统更易于使用。例如strpos()等函数的返回值可以是整数或布尔值,这比严格设计的返回整数或抛出异常的方法更容易使用。
看看PHP语言的发展,几乎所有新功能都是以开发人员的需求为基础,而不是追求“正确”。更多地关注严格的类型和异常错误是一种更正确的方式。尽管如此,短箭头函数、属性和枚举之类功能才是开发人员希望简化对代码。
7. PHP 不必保持一致性
设计不能过于不一致。在某些情况下,为了简单性,可以牺牲一致性。
我从不会说PHP具有一致性,但它的一致性已经足够了。提及数组与字符串函数,人们可能会抱怨Needle/haystack的参数顺序。不过一般来说,数组函数是一致的,字符串函数是一致的。与保持语言的一致性相比,保持与底层 C 库的一致更简单。
PHP在其他方面也很一致。比如strpos()函数,PHP的函数在遇到错误时,就会返回FALSE,这一点非常一致。不一定正确,但很一致。函数命名是否带下划线往往也是与底层库保持一致。
PHP语言为了简单性牺牲了一致性,但即使没有规范,它也在努力在有意义的地方保持一致。
8. PHP 的完整性符合一定的需求
设计必须尽可能涵盖重要情况。
在某些时候,PHP尽可能保持完备,它符合设计的需求:编写Web应用程序。PHP的设计目标从来不是成为一种适用于所有编程问题的语言。尽管如此,由于简单性,PHP也适用于Web之外的编程。PHP最初的目的就是为Web编程提供最基本的功能,而且一直延续至今。
核心语言的变化主要由开发人员的需求驱动。整个社区提出修改意见,然后经由社区投票,决定新功能被拒绝、修改还是接受。该语言中的大部分创新都是因为我们需要更快地完成工作。即使我们窃取其他语言的特性,也是因为这些特性能够减轻开发人员的负担,很少是因为另一种语言“更正确”。
如今你可以利用PHP构建Web应用程序,而且在接下来的五年内你还可以继续用PHP制作Web应用程序,只不过会添加一些新功能。然而,这种语言本身已经达成所需。如果有需要,我们可以随时添加新功能或修改语言。
9. 越糟越好吗?
Gabriel承认,“越糟越好”的思想是说设计看起来很糟糕,可能不应该作为更好的选择。唯一的问题是,审视这两种设计理念,比较学院派与“正确的方法”,那么自然“越糟越好”是更灵活的选择,还有“具有更好的生存特性”。看看 PHP,它证实了“越糟越好”的思想。
在此期间,Gabriel承认他也很犹豫哪种理念更好。作为一个社区,PHP不断争论我们应该正确地做事还是继续简单地做事。我们有像Laminas这样的框架,以经典的计算机科学方式构建的库,还有Laravel这样的框架关注开发人员的体验和速度。可以说PHP二者兼具。
下次再听到有人批评PHP,就随他们去吧。这种语言确实很糟糕,但PHP的长盛不衰以及广泛使用证明了这样一个事实:“正确的方式”未必比“最糟”更好。如果有人抱怨你使用的框架,也无需在意,从长远来看这无关紧要。更重要的是,选择一种舒服的设计理念,并告诉自己“越糟越好”。
参考链接:
有道无术,术可成;有术无道,止于术
欢迎大家关注Java之道公众号