使用 PHP 8 扩展中删除的功能

在本节中,我们将了解 PHP 8 扩展中已删除的功能。这些信息对于避免编写在 PHP 8 中无法运行的代码极其重要。此外,对已移除功能的了解有助于为 PHP 8 迁移准备现有代码。

下表概述了已移除的扩展功能:

Table 1. Table 8.2 – Functions removed from PHP 8 extensions
扩展 移除函数 建议替换

Exif

read_exif_data()

exif_read_data()

GD

image2wbmp()

png2wbmp()

jpeg2wbmp()

正常创建图片,然后使用 imagewbmp()

GMP

gmp_random()

gmp_random_range()

gmp_random_bits()

Imap

imap_header()

imap_headerinfo()

LDAP

ldap_sort()

$res = ldap_search(); usort($res);

ldap_control_paged_result()

ldap_control_paged_result_response()

$res = ladp_search(); 使用 FilterIterator 实现分页

OCI8

oci_internal_debug()

ociinternaldebug()

None

Zlib

gzgetss()

strip_tags(gzgets())

上表提供了一个有用的已删除函数列表。在迁移 PHP 8 之前,请使用该列表检查您的现有代码。

现在让我们来看看对 mbstring 扩展的一个潜在的严重更改。

发现 mbstring 扩展更改

mbstring 扩展有两处重大改动,可能会造成大量向后兼容的代码中断。第一个变化是删除了大量的便利别名。第二个重大变化是删除了对 mbstring PHP 函数重载功能的支持。让我们先看看被移除的别名。

处理删除的 mbstring 扩展别名

应一些开发人员的要求,负责该扩展的 PHP 开发团队慷慨地创建了一系列别名,用 mb*() 代替 mb_*()。批准这一请求的确切理由已被时间所遗忘。然而,每次需要更新扩展时,支持如此大量别名的负担都会浪费大量时间。因此,PHP 开发团队投票决定在 PHP 8 中删除 mbstring 扩展中的这些别名。

下表列出了被移除的别名,以及替代它们的函数:

Table 2. Table 8.3 – Removed mbstring aliases
别名 替代

mbereg

mb_ereg()

mbereg_match

mb_ereg_match()

mbereg_replace

mb_ereg_replace

mbereg_search

mb_ereg_search()

mbereg_search_getpos

mb_ereg_search_getpos()

mbereg_search_getregs

mb_ereg_search_getregs()

mbereg_search_init

mb_ereg_search_init()

mbereg_search_pos

mb_ereg_search_pos()

mbereg_search_regs

mb_ereg_search_regs()

mbereg_search_setpos

mb_ereg_search_setpos()

mberegi

mb_eregi()

mberegi_replace

mb_eregi_replace()

mbregex_encoding

mb_regex_encoding()

mbsplit

mb_split()

现在让我们看看字符串处理中的另一个重大变化,即函数重载。

使用 mbstring 扩展函数重载

如果 php.ini 指令 mbstring.func_overload 被赋值,函数重载功能允许标准 PHP 字符串函数(例如 substr())被 mbstring 扩展函数(例如 mb_substr())悄悄替换。该指令的赋值形式为位标志。根据该标志的设置,mail()str*()substr()split() 函数可能会被重载。该功能在 PHP 7.2 中已被弃用,并在 PHP 8 中被删除。

此外,与此功能相关的三个 mbstring 扩展常量也已删除。这三个常量是 MB_OVERLOAD_MAILMB_OVERLOAD_STRINGMB_OVERLOAD_REGEX

有关该功能的更多信息,请访问以下链接: https://www.php.net/manual/en/mbstring.overload.php

任何依赖于此功能的代码都会被破坏。避免严重应用程序故障的唯一方法是重写受影响的代码,并用预期的 mbstring 扩展函数替换被静默替换的 PHP 核心字符串函数。

在下面的示例中,当启用 mbstring.func_overload 时,PHP 7 会报告 strlen()mb_strlen() 的相同值:

// /repo/ch08/php7_mbstring_func_overload.php
$str = 'วนั น้ีสบายดีไหม';
$len1 = strlen($str);
$len2 = mb_strlen($str);
echo "Length of '$str' using 'strlen()' is $len1\n";
echo "Length of '$str' using 'mb_strlen()' is $len2\n";

下面是 PHP 7 的输出结果:

root@php8_tips_php7 [ /repo/ch08 ]#
php php7_mbstring_func_overload.php
Length of 'วนั น้ีสบายดีไหม' using 'strlen()' is 45
Length of 'วนั น้ีสบายดีไหม' using 'mb_strlen()' is 15

root@php8_tips_php7 [ /repo/ch08 ]#
echo "mbstring.func_overload=7" >> /etc/php.ini

root@php8_tips_php7 [ /repo/ch08 ]#
php php7_mbstring_func_overload.php
Length of 'วนั น้ีสบายดีไหม' using 'strlen()' is 15
Length of 'วนั น้ีสบายดีไหม' using 'mb_strlen()' is 15

从前面的输出中可以看出,一旦在 php.ini 文件中启用了 mbstring.func_overload 设置,strlen()mb_strlen() 所报告的结果是完全相同的。这是因为对 strlen() 的调用被静默地转移到了 mb_strlen()。在 PHP 8 中,输出(未显示)显示了两种情况下的结果,因为 mbstring.func_overload 设置被忽略了。strlen() 报告的长度为 45,而 mb_strlen() 报告的长度为 15。

要确定您的代码是否易受此向后兼容中断的影响,请检查 php.ini 文件,查看 mbstring.func_overload 设置是否为零以外的值。

现在,您已经知道应从何处查找与 mbstring 扩展相关的潜在代码中断。现在,我们将注意力转向 Reflection 扩展中的更改。

重写使用 Reflection*::export() 的代码

Reflection 扩展中,PHP 8 与早期版本的一个重要区别是删除了所有 Reflection*::export() 方法!这一变化的主要原因是,简单地回传 Reflection 对象所产生的结果与使用 export() 所产生的结果完全相同。

如果您的代码目前使用了任何 Reflection*::export() 方法,则需要重写代码,改用 __toString() 方法。

发现其他已弃用的 PHP 8 扩展功能

在本节中,我们将回顾 PHP 8 扩展中其他一些值得注意的重要废弃功能。首先,我们来看 XML-RPC。

XML-RPC 扩展的更改

在 PHP 8 之前的 PHP 版本中,XML-RPC 扩展是核心的一部分,始终可用。从 PHP 8 开始,该扩展已悄然转移到 PHP 扩展社区库 (PECL) ( http://pecl.php.net/ ),不再默认包含在标准 PHP 发行版中。您仍然可以安装和使用该扩展。通过扫描 PHP 内核中的扩展列表,可以很容易地确认这一变化: https://github.com/php/php-src/tree/master/ext

这不会造成向后兼容的代码中断。但是,如果您执行标准的 PHP 8 安装,然后迁移包含 XML-RPC 引用的代码,您的代码可能会生成致命的错误信息,并显示 XML-RPC 类和/或函数未定义的信息。在这种情况下,只需使用 pecl 或其他通常用于安装非核心扩展的方法安装 XML-RPC 扩展即可。

现在,我们将注意力转向 DOM 扩展。

对 DOM 扩展进行的更改

自 PHP 5 起,文档对象模型(DOM)扩展的源代码库中就包含了许多从未实现过的类。在 PHP 8 中,我们决定将 DOM 作为一个活的标准来支持(就像 HTML 5 一样)。所谓 "活标准",是指没有一系列固定的发布版本,而是不断发布新版本,以跟上网络技术的发展。

有关提议的 DOM 生活标准的更多信息,请参阅此参考资料: https://dom.spec.whatwg.org/ 。有关将 PHP DOM 扩展移到生活标准基础上的精彩讨论,请参阅第 9 章 "掌握 PHP 8 最佳实践" 中的 "使用接口和特质" 部分。

主要由于向 living standard 的转变,以下未实现的类已从 PHP 8 的 DOM 扩展中删除:

  • DOMNameList

  • DOMImplementationList

  • DOMConfiguration

  • DOMError

  • DOMErrorHandler

  • DOMImplementationSource

  • DOMLocator

  • DOMUserDataHandler

  • DOMTypeInfo

这些类从未被实现过,这意味着你的源代码不会受到任何向后兼容性中断的影响。

现在让我们来看看 PHP PostgreSQL 扩展中的弃用。

对 PostgreSQL 扩展所做的更改

除了表 8.5 - PHP 8 扩展中已废弃的功能(稍后显示)外,还需要注意 PHP 8 PostgreSQL 扩展中的几十个别名已被废弃。与从 mbstring 扩展中移除的别名一样,我们在本节中介绍的别名在别名名称的后半部分没有下划线字符。

本表总结了已删除的别名,以及应调用哪些函数来替代它们:

Table 3. Table 8.4 – Deprecated functionality in PostgreSQL extension
别名 替代

pg_errormessage()

pg_last_error()

pg_numrows()

pg_num_rows()

pg_numfields()

pg_num_fields()

pg_cmdtuples()

pg_affected_rows()

pg_fieldname()

pg_field_name()

pg_fieldsize()

pg_field_size()

pg_fieldtype()

pg_field_type()

pg_fieldnum()

pg_field_num()

pg_result()

pg_fetch_result()

pg_fieldprtlen()

pg_field_prtlen()

pg_fieldisnull()

pg_field_is_null()

pg_freeresult()

pg_free_result()

pg_getlastoid()

pg_last_oid()

pg_locreate()

pg_lo_create()

pg_lounlink()

pg_lo_unlink()

pg_loopen()

pg_lo_open()

pg_loclose()

pg_lo_close()

pg_loread()

pg_lo_read()

pg_lowrite()

pg_lo_write()

pg_loreadall()

pg_lo_read_all()

pg_loimport()

pg_lo_import()

pg_loexport()

pg_lo_export()

pg_setclientencoding()

pg_set_client_encoding()

pg_clientencoding()

pg_client_encoding()

请注意,通常很难找到有关弃用的文档。在这种情况下,你可以查阅 PHP 7.4 到 PHP 8 的迁移指南: https://www.php.net/manual/en/migration80.deprecated.php##migration80.deprecated.psql 。否则,可以在 C 源代码文档块中查找 @deprecation 注释: https://github.com/php/php-src/blob/master/ext/pgsql/pgsql.stub.php 。下面是一个例子:

/**
* @alias pg_last_error
* @deprecated
*/
function pg_errormessage(
    ?PgSql\Connection $connection = null): string {}

在本节的最后一部分,我们总结了 PHP 8 扩展中已废弃的功能。

PHP 8 扩展程序中已废弃的函数

最后,为了让您更容易识别 PHP 8 扩展中被弃用的功能,我们提供了一份总结。下表总结了 PHP 8 扩展中被弃用的功能:

Table 4. Table 8.5 – Deprecated functionality in PHP 8 extensions
扩展 过时函数 建议替换

Enchant

enchant_dict_add_to_personal()

enchant_dict_is_in_session()

enchant_broker_free()

enchant_broker_free_dict()

enchant_broker_set_dict_path()

enchant_broker_get_dict_path()

enchant_dict_add()

enchant_dict_is_added()

unset($enchantObject)

(same)

不再支持

(same)

OCI8

OCI-Lob

OCI-Collecction

OCILob

OCICollection

ODBC

odbc_connect()

odbc_exec()

不再重用链接

flags参数被移除

PostgreSQL

PGSQL_LIBPQ_VERSION_STR

pg_connect()

pg_lo_import(),pg_lo_export()

pg_fetch_all()

PGSQL_LIBPQ_VERSION

现在必须使用连接字符串

第一个参数现在是连接

如果没有结果,则返回空数组

Reflection

ReflectionParameter::getClass()

ReflectionParameter::isArray()

ReflectionParameter::isCallable()

ReflectionParameter::isDisabled()

ReflectionParameter::getType()

(same)

(same)

None

LibXML

libxml_disable_entity_loader()

None: no longer needed

我们将使用 PostgreSQL 扩展来说明已过时的功能。在运行代码示例之前,您需要在 PHP 8 Docker 容器中进行少量设置。步骤如下:

  1. 在 PHP 8 Docker 容器中打开一个命令 shell。在命令 shell 中使用此命令启动 PostgreSQL:

    /etc/init.d/postgresql start
  2. 接下来,切换到 su postgres 用户。

  3. 提示变为 bash-4.3$。在此输入 psql 进入 PostgreSQL 交互终端。

  4. 接下来,从 PostgreSQL 交互终端发出以下命令,创建并填充一个示例数据库表:

    CREATE DATABASE php8_tips;
    \c php8_tips;
    \i /repo/sample_data/pgsql_users_create.sql
  5. 下面是整个命令链的回放:

    root@php8_tips_php8 [ /repo/ch08 ]# su postgres
    bash-4.3$ psql
    psql (10.2)
    Type "help" for help.
    postgres=# CREATE DATABASE php8_tips;
    CREATE DATABASE
    postgres=# \c php8_tips;
    You are now connected to database "php8_tips"
    as user "postgres".
    php8_tips=# \i /repo/sample_data/pgsql_users_create.sql
    CREATE TABLE
    INSERT 0 4
    CREATE ROLE
    GRANT
    php8_tips=# \q
    bash-4.3$ exit
    exit
    root@php8_tips_php8 [ /repo/ch08 ]#
  6. 现在我们定义一个简短的代码示例来说明刚才讨论的弃用概念。请注意,在下面的代码示例中,我们为一个不存在的用户创建了一个 结构化查询语言(SQL) 语句:

    // /repo/ch08/php8_pgsql_changes.php
    $usr = 'php8';
    $pwd = 'password';
    $dsn = 'host=localhost port=5432 dbname=php8_tips '
        . ' user=php8 password=password';
    $db = pg_connect($dsn);
    $sql = "SELECT * FROM users WHERE user_name='joe'";
    $stmt = pg_query($db, $sql);
    echo pg_errormessage();
    $result = pg_fetch_all($stmt);
    var_dump($result);
  7. 以下是前面代码示例的输出:

    root@php8_tips_php8 [ /repo/ch08 ]#
    php php8_pgsql_changes.php
    Deprecated: Function pg_errormessage() is
    deprecated in /repo/ch08/php8_pgsql_changes.php on
    line 22
    array(0) {}

输出结果中有两点值得注意:pg_errormessage() 已被弃用;当查询没有返回结果时,返回的不是 FALSE 布尔值,而是一个空数组。不要忘记使用该命令停止 PostgreSQL 数据库:

/etc/init.d/postgresql stop

在了解了各种 PHP 8 扩展中被弃用的功能之后,我们将注意力转向与安全相关的弃用功能。