使用 PHP 8 扩展中删除的功能
在本节中,我们将了解 PHP 8 扩展中已删除的功能。这些信息对于避免编写在 PHP 8 中无法运行的代码极其重要。此外,对已移除功能的了解有助于为 PHP 8 迁移准备现有代码。
下表概述了已移除的扩展功能:
扩展 | 移除函数 | 建议替换 |
---|---|---|
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
扩展中的这些别名。
下表列出了被移除的别名,以及替代它们的函数:
别名 | 替代 |
---|---|
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_MAIL
、MB_OVERLOAD_STRING
和 MB_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()
方法。
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
扩展中移除的别名一样,我们在本节中介绍的别名在别名名称的后半部分没有下划线字符。
本表总结了已删除的别名,以及应调用哪些函数来替代它们:
别名 | 替代 |
---|---|
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 扩展中被弃用的功能:
扩展 | 过时函数 | 建议替换 |
---|---|---|
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 容器中进行少量设置。步骤如下:
-
在 PHP 8 Docker 容器中打开一个命令 shell。在命令 shell 中使用此命令启动 PostgreSQL:
/etc/init.d/postgresql start
-
接下来,切换到
su postgres
用户。 -
提示变为 bash-4.3$。在此输入
psql
进入 PostgreSQL 交互终端。 -
接下来,从 PostgreSQL 交互终端发出以下命令,创建并填充一个示例数据库表:
CREATE DATABASE php8_tips; \c php8_tips; \i /repo/sample_data/pgsql_users_create.sql
-
下面是整个命令链的回放:
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 ]#
-
现在我们定义一个简短的代码示例来说明刚才讨论的弃用概念。请注意,在下面的代码示例中,我们为一个不存在的用户创建了一个 结构化查询语言(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);
-
以下是前面代码示例的输出:
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 扩展中被弃用的功能之后,我们将注意力转向与安全相关的弃用功能。