了解 FFI
FFI 的主要目的是让任何特定的编程语言都能从用其他语言编写的外部库中整合代码和函数调用。这方面的一个早期例子是,20 世纪 80 年代的微机可以使用 PEEK 和 POKE 命令将汇编语言整合到原本缓慢的初学者通用符号指令代码(BASIC)编程语言脚本中。与许多其他语言不同的是,PHP 在 PHP 7.4 之前并不具备这种功能,尽管从 2004 年就开始讨论了。
为了对 PHP 8 中的 FFI 有一个全面的了解,我们有必要离题看看为什么 FFI 要花这么长的时间才被完全采用到 PHP 语言中。此外,我们还有必要快速了解一下 PHP 扩展的总体情况,以及与 C 语言代码协同工作的能力。我们首先来看看 PHP 和 C 语言之间的关系。
PHP 和 C 语言的关系
C 语言由丹尼斯-里奇(Dennis Ritchie)于 1972 年底在贝尔实验室开发。从那时起,尽管其面向对象的表兄弟 C++ 已经问世,但 C 语言仍然在编程语言领域占据主导地位。PHP 本身就是用 C 语言编写的;因此,直接加载 C 语言共享库、直接访问 C 语言函数和数据结构的能力对 PHP 语言来说是一个极其重要的补充。
在 PHP 语言中引入 FFI 扩展后,PHP 就具备了加载并直接使用 C 结构和 C 函数的能力。为了明智地决定在何时何地使用 FFI 扩展,我们先来了解一下 PHP 扩展的一般情况。
了解 PHP 扩展
PHP 扩展,顾名思义,是对 PHP 语言的扩展。每个扩展都可以添加面向对象编程(OOP)类和程序级函数。例如,GD 扩展处理图形图像操作,而 PDO 扩展处理数据库访问。
打个比方,请看一家医院。医院里有急诊科、外科、儿科、骨科、心内科、X 光科等科室。每个科室都是独立的,都有各自的用途。这些部门共同组成了医院。同样,PHP 就像医院,其扩展部分就像各个科室。
并非所有的扩展都是一样的。有些扩展被称为核心扩展,在安装 PHP 时总是可用的。其他扩展则必须手动下载、编译和启用。现在让我们来看看核心扩展。
访问 PHP 核心扩展
PHP 核心扩展直接包含在主 PHP 源代码库中,位于: https://github.com/php/php-src/tree/master/ext 。进入该网页,会看到一个子目录列表,如下图所示。每个子目录都包含特定扩展的 C 语言代码:

因此,在服务器上安装 PHP 时,所有的核心扩展也会同时编译和安装。现在,我们将简要介绍不属于核心的扩展。
检查 PHP 非核心扩展
不属于核心部分的 PHP 扩展通常由特定的供应商维护(微软就是一个例子)。通常,非核心扩展被认为是可选的,不会被广泛使用。
一旦某个非核心扩展的使用频率越来越高,它就很有可能最终被移植到核心中。这样的例子不胜枚举。最近的例子是 JSON 扩展:它现在不仅是核心的一部分,而且在 PHP 8 中也不能再禁用了。
核心扩展也有可能被移除。mcrypt
扩展就是一个例子。该扩展在 PHP 7.1 中被弃用,因为它所依赖的底层库已经废弃了 9 年多。在 PHP 7.2 中,它被正式从核心中移除。现在我们来看看在哪里可以找到非核心扩展。
查找非核心扩展
这时,你可能会问一个合乎逻辑的问题: 从哪里可以获得非核心扩展?一般来说,非核心扩展可直接从供应商、github.com 或本网站 http://pecl.php.net/ 获取。多年来一直有人抱怨 pecl.php.net 包含过时和未维护的代码。虽然这种说法部分属实,但本网站上确实存在最新的、积极维护的代码。
举例来说,如果你看看 MongoDB 的 PHP 扩展,就会发现最近一次发布是在 2020 年 11 月底。下面的截图显示了该扩展的 PHP 扩展社区库(PECL)网站页面:

在许多情况下,供应商更愿意保留对扩展的完全控制权。这意味着你需要到他们的网站上获取 PHP 扩展。Microsoft SQL Server 的 PHP 扩展程序就是一个例子,其统一资源定位器(URL)为: https://docs.microsoft.com/en-us/sql/connect/php/downloaddrivers-php-sql-server?view=sql-server-ver15 。
本小节的主要内容是通过扩展增强 PHP 语言。扩展是用 C 语言编写的。因此,在 PHP 脚本中直接对原型扩展的逻辑进行建模的能力是极其重要的。现在让我们来看看应该在哪些地方使用 FFI。