PHP 杂谈之它凉了吗

前言

在学校就开始接触 PHP 开发的我,毕业之后作为一枚 PHP 程序员,开发和维护过几个系统。

兜兜转转,身边不少写 PHP 的同学也已经入了 Golang 的坑,而我入了 Golang 的坑然后又跳了出来,现在依然在写 PHP。

注:当然个人开源项目以及未来的南洋站,我也还是要用 Golang 写后端的

踩一抬一的说法在网上充斥着,众人都说 Golang 大法好,那 PHP 是不是真的没出路了呢?关于这个问题,我没有答案,我只想聊一聊我所了解到的情况。

PHP 版本

目前,主流的 PHP 版本分别是 PHP5 和 PHP7。由于 PHP7 性能高及引入了诸多新特性(NULL 合并运算符、统一的错误处理机制等),新项目一般会选择 PHP7,而 PHP5 更多是老项目使用。

PHP 版本生命周期

首先,看一段摘至 PHP 官网 的文本。

Each release branch of PHP is fully supported for two years from its initial stable release. During this period, bugs and security issues that have been reported are fixed and are released in regular point releases.

After this two year period of active support, each branch is then supported for an additional year for critical security issues only. Releases during this period are made on an as-needed basis: there may be multiple point releases, or none, depending on the number of reports.

Once the three years of support are completed, the branch reaches its end of life and is no longer supported. A table of end of life branches is available.

翻译为人话:每个 PHP 版本自稳定版发行起,有三年的支持期,前两年会积极地修复功能性 Bug 和安全相关的问题,之后一年则仅修复严重的安全问题

版本 发行日期 活跃支持期截止日期 安全维护截止日期
7.2 2017 年 11 月 30 日 2019 年 11 月 30 日 2020 年 11 月 30 日
7.3 2018 年 12 月 6 日 2020 年 12 月 6 日 2021 年 12 月 6 日
7.4 2019 年 11 月 28 日 2021 年 11 月 28 日 2022 年 11 月 28 日

市场主流版本

由于现在的 PHP 开发大多会选择流行的框架进行开发,而不是纯手抡一个项目。所以,可以通过框架对 PHP 版本的要求,大致了解到目前的主流。

框架 GitHub Stars 要求 出处
Laravel 59.7k >= 7.2.5 Server Requirements
Symphony 23.5k >= 7.2.5 Technical Requirements
CodeIgniter 3 18k >= 5.4.8 Composer Requirements
Yii 2 13.4k >= 5.4 PHP Requirements
Slim 10.7k >= 7.2 System Requirements
Phalcon 4 10.2k >= 7.2 Requirements
CodeIgniter 4 2.8k >= 7.2 Server Requirements
ThinkPHP 6 2.1k >= 7.1.0 安装要求

注:以上表格的框架按照 GitHub 星标数由高到低排序,星标数量收集于 2020 年 6 月 20 日。

从上述表格可以看到,基本上主流的框架都要求 PHP 版本不低于 7.2,由此可以推断出:现代的 PHP 开发多使用不低于 7.2 的 PHP 版本。

PHP 框架

在上一节中,有提到目前 GitHub 主流的框架,本文针对这些框架做一些介绍和对比。

注:由于 Swoole 和 Phalcon 已经不是纯粹的代码框架,不在本文讨论范围内。

Laravel

The PHP Framework for Web Artisans

Laravel is a web application framework with expressive, elegant syntax. We’ve already laid the foundation — freeing you to create without sweating the small things.

首先是 Laravel,一个被称为世界上最优雅的框架,由 Taylor Otwell 创建并开源在 GitHub。

Laravel 在 2011 年 6 月 9 日发布了第一个 Beta 版本,但从 2013 年的 Laravel 4 发行之后,才开始真正流行。经过多年的迭代,目前 Laravel 最新版本是 7.0,最新 LTS 版本是 6.0。

它的优雅设计(如服务容器)和丰富的脚手架工具,为它赢来了几乎是所有的 PHPer 的关注:

  • 从 GitHub 的数据来看,它的 Star 数是第二名的 2 倍多
  • 目前主流的 PHP 包开发,基本都会考虑优先适配 Laravel
  • Laravel 社区丰富,比如国内的 Laravel China

但它并不是没有缺点。它的缺点恰好在于使用了过多的设计模式,所以有一定的上手门槛。

Symfony

Symfony 是一款基于 MVC 架构的 PHP 框架,致力于减少重复代码的编写,以加速 Web 应用的开发和维护。

—— 摘至维基百科

目前 Symfony 的最新版本是 4.3,最新 LTS 版本是 3.4。作为 PHP 框架星标数的第二名,Symfony 也同样使用了不少的设计模式,以减少重复代码的编写。

虽然 Symfony 官网上写道「Symfony 是一组可复用的 PHP 组件,它还是一个用于 web 项目的 PHP 框架」,但个人认为它作为组件存在的意义是要大于它作为框架的意义的。

对 Laravel 有了解的同学应该知道,Laravel 框架其实用了不少 Symfony 的组件,像 symfony/consolesymfony/http-foundationsymfony/http-kernelsymfony/routing 等组件可以在 Laravel 的 依赖包 中找到。

CodeIgniter

CodeIgniter 框架简称 CI 框架,因为简单易用而流行。在很多早期的 PHP 开源项目中,或多或少有 CI 的影子,比如开源电子商城 OpenCart、项目管理系统 ZenTao 等。

但由于 PHP 工具的进步和众多框架的推出,而 CI 对于现代 PHP 技术和先进模式的使用缓慢,它已经逐渐从框架世界的领头羊变成追随者。

2010 年基本是 CI 框架的巅峰,随着 Laravel 逐渐流行,CI 的市场逐渐被瓜分。在 2015 年下旬,CI 团队终于决定做出一些改变,以跟上 PHP 世界的发展速度。

随后,核心负责在官方社区发了一个关于 CI4 蓝图的帖子,并开始了漫长的开发过程。一晃好多年,直到 2020 年 5 月,CI4 才正式推出。而此时,PHP 世界其实已经不太需要 CI4 了。

如果对比 CI4 和 Laravel 的项目结构,会发现 CI4 和 Laravel 神似,比如:CI4 的 spark 工具和 Laravel 的 artisan 工具神似、CI4 和 Laravel 的数据迁移工具。

无论是说 CI4 抄 Laravel 作业也好,还是 CI4 和 Laravel 都是抄 Rails 作业,两者的设计思想没有大的差别。但是从生态上,CI4 明显要落后几年。

Codeigniter 4 was released On February 24, 2020, birthday of Jim Parry who was the project lead of Codeigniter 4 and died on January 15, 2020. After that, the project continues until today with other project lead.

—— 摘自维基百科

伴随着 CI4 原负责人的离世,加上 CI4 在 GitHub 上更新频率很低,让人不免对这个框架的未来感到担忧。

Yii2/Slim/ThinkPHP

Yii2 和 Slim 放到一起讲,主要是因为它们目前占据的市场份额较小,关注度不高,现在基本也很少讨论。值得一提的是,Slim 框架足够的轻量,一般适用于想快速写一个简单的 PHP 应用。

按照关注度来看,ThinkPHP 相比其它几个,完全没有竞争力。但它有几个优点:

  • 国产开源软件,意味着原生中文文档和中文社区
  • 采用 PHP7 强类型(严格模式)
  • 支持 Swoole
  • 支持多应用

小结

现代框架在很多方面都很类似了,比如使用命名空间、composer 包管理、自动加载机制等,起码不会是「难用」的框架。

Laravel Symfony CI ThinkPHP
诞生时间 2011 2007 2006 2006
开源协议 MIT MIT MIT Apache2
最新 LTS 版本 6.x 4.4 N/A 5.1
最新 LTS 维护截止日期 2022/09/03 2023/11/01 N/A 2021/01/01
最新版本 7.x 5.1 4.0 6.0
更新频率 快(一周多次) 快(一周多次) 慢(多月一次) 慢(多月一次)
社区活跃度
组件丰富程度

Google Trends 中可以看到,各框架的热度排序为 Laravel > CI > Symfony > ThinkPHP;从 Stack Overflow Trends 来对比,也可以看到 Laravel 以压倒性的优势领先于其它几个框架。

综合来看,Laravel 无疑已是 PHP 框架世界中的王者。

Composer

很多比较旧的 PHP 项目,都没有所谓的包管理机制:通常都是通过拷贝粘贴的方式,引入和管理依赖。像鹅厂这样的 C++ 大厂,会比较习惯于用 C++ 写 PHP 扩展的方式,引入依赖。

写扩展的方式对于一些性能要求很高的场合,是非常明智的。但由于扩展的编译强依赖于 PHP 版本和环境,使得 PHP 升级阻力极大。

注:PHP7.4 版本的 FFI 新特性可能会改善这种情况

Composer 的出现,解决了这个问题。Composer 的设计灵感来源于 node 的 npm 和 ruby 的 bundler,通过 composer.json 文件指定依赖库和版本,安装之后通过 composer.lock 锁定版本。

PSR

PSR 是 PHP Standard Recommendations (PHP 推荐标准)的简写,由 PHP FIG 组织制定的 PHP 规范,是 PHP 开发的实践标准。

对于团队开发而言,代码规范是比较需要关心的。统一的代码规范,可以增强代码的可读性,同时也是提高项目维护性的重要措施。想象一下,如果你要对一个多人维护的项目进行开发,而里面的代码风格各异,你是一种什么感受。

目前 PSR 中关于编码规范的分别是 PSR-1、PSR-2 和 PSR-12,其中 PSR-2 已废弃。在代码规范这块,Golang 做得比较多,制定了统一的官方代码风格,并且推出了 gofmt 工具,帮助开发者格式化代码到统一风格。

PHP 这块也有不少的 IDE 插件可以帮助开发者格式化代码,比如 PHPStorm 可以设置使用 PSR-1/PSR-12 代码风格,并支持整合 phpcs 提供代码风格提示和自动校正功能。

测试

测试是用来保证软件质量的一种手段,PHP 语言中最出名的测试框架当属 PHPUnit。像 Laravel、Symfony 等框架都使用 PHPUnit 进行单元测试。

尽管测试的好处很多,但根据我经历的项目来看,大多数程序员是懒得写测试代码的,遇到比较紧急的项目,就更不可能写了。

对于简单的逻辑,写测试代码可能还不会很费时间,无非就是把用例梳理清楚。但对于有外部依赖的情况,比如依赖 DB 或者是 HTTP 服务等,就不得不写一堆的 Mock 代码和用例。

当被测试代码中存在大量的 new XXX() 时,Mock 过程就变得更加繁琐。说不好为了凑测试代码,还要魔改原来的代码,令人头秃。

如果用 Laravel 框架,由于其服务容器的设计模式,所有类的实例化都可以通过全局变量 app 托管,这种情况就会好很多。只需要在测试代码中 Hack 这个全局变量,可以较轻松的 Mock 依赖服务。

性能

语言的性能

PHP7 通过一系列的细节优化,降低了内存使用,提升了运行性能,这点在网上都很多评测文章,相信大家有目共睹。PHP8 有望引入 JIT,可能会有更好的性能提升。

所以,如果有人在吐槽 PHP 的性能差,多半是针对现有 Nginx+php-fpm 这种工作方式下 PHP 的并发性能。在这种工作方式下,每来一个请求,都需要加载一次 PHP 代码,执行结束后又销毁。

![PHP Life Cycle](/something-about-php/PHP Life Cycle.png)

当然,也可以通过 OpCache 缓存 OpCode 的方式,减少每次请求的执行时间。尽管如此,由于没有跨请求的「全局变量」,也就没有数据库连接池的概念,每次需要连接数据库时,都需要新建连接,相对而言比较低效。

OpCode

相比于 Golang 及 Swoole4 的协程机制,Nginx+php-fpm 这种通过多进程处理并发请求的模式,使用的资源要多得多。所以,经常有人说「Golang 的并发能力要比 PHP 要强 10 倍」。

框架的性能

前一阵,我也在了解框架之间的性能对比。

稍微谷歌一下,你就会发现网上充斥着雷同的评测方式和评测结果,大概就是最流行的 Laravel 框架被 Slim、CI3 等框架打击得一无是处。

那么,真相是这样吗?我认为不是的,因为他们的对比方式本身就出错了。

这些测评大多基于 Hello World 级别的无业务逻辑、无数据库连接的场景。而 Laravel 默认开启 Session 及 CSRF 机制,每次请求都会有 IO 操作,显然不用对比都会落于下风。

在众多测评文章中,我发现这篇 The Definitive PHP Benchmarks 文章用的方式比较客观,也更贴近于大多数业务场景。其中,Laravel 和 CI3 的测试条件几乎是一样的。

Laravel:

  • Tested URL: / (homepage)
  • The post contains, title, author name, and main content. The database contains 1 table “posts”. The table contains 6 columns “post_title”, “post_content”, “post_author”, “created_at” and “updated_at.”
  • The tested URL connected to the database and showing all the posts on the table. Furthermore, the Laravel app contains 1 route and 1 controller to display these content.
  • Laravel 5.8.35 no longer supports PHP 5.6 or PHP 7.0. Laravel 6.7.0 no longer supports PHP 5.6, 7.0, or 7.1.

CodeIgniter:

  • Tested URL: / (homepage)
  • Note: The post contains, title, author name, and main content. The database contains 1 table “posts”. The table contains 6 columns “post_title”, “post_content”, “post_author”, “created_at” and “updated_at.”
  • The tested URL connected to the database and showing all the posts on the table. Furthermore, the CodeIgniter app contains 1 route and 1 controller to display these content.
  • CodeIgniter 4.0-rc.3 doesn’t support PHP 5.6, 7.0, or 7.1.

经过测试,CI3 这个号称极轻量的框架在 PHP7.4 中的极限 QPS 是 394.96,而 Laravel 5.8.35 在 PHP7.4 中的极限 QPS 是 402.39。感兴趣的同学,可以科学上网了解下这篇博文。

Laravel Benchmarks

CodeIgniter Benchmarks

通过这样一对比,其实可以发现,在有 DB 连接的情况下,框架重还是轻量对并发能力影响不大。当然,生产环境中还是建议使用 OpCache 加速 PHP 代码的执行。

小结

讲了那么多,那么 PHP 要凉了吗?它还是世界上最好的语言吗?

我认为不会凉,在 PHP 最近更新的版本中,我或多或少看到了 NodeJS 的影子,它在借鉴其它语言的优秀特性。

相信随着 PHP 语言的发展,或许它在某一天,引入了 JIT、也解决了令人诟病的并发问题。

只是不知道,会有多少人坚守并等到那一天的到来。

参考资料

  • PHP Unit 官网
  • OpCode Cache 与 JIT 的区别
  • The Definitive PHP 5.6, 7.0, 7.1, 7.2, 7.3, and 7.4 Benchmarks (2020)