不向后兼容的变更
PHP 内核
$GLOBALS 访问限制
现在访问 $GLOBALS 数组受到一些限制。对单个数组元素的读写访问
$GLOBALS['var']
与之前一样。也将继续支持对整个数组
$GLOBALS 的只读访问。但是,不再支持对整个
$GLOBALS 数组的写访问。例如
array_pop($GLOBALS)
将返回错误。
在继承的方法中 static 变量的用法
当一个方法使用继承的(而不是重写的)静态变量时,继承的方法将与父级共享这个静态变量。
<?php
class A {
public static function counter() {
static $counter = 0;
$counter++;
return $counter;
}
}
class B extends A {}
var_dump(A::counter()); // int(1)
var_dump(A::counter()); // int(2)
var_dump(B::counter()); // int(3),之前是 int(1)
var_dump(B::counter()); // int(4),之前是 int(2)
?>
在强制参数之前指定可选参数
现在在强制参数之前指定可选参数都被视为强制参数,即使是使用命名参数调用也是如此。自 PHP 8.0.0 起至 PHP 8.1.0 之前,在定义时会发出弃用通知,但能成功调用。自 PHP 8.1.0 起,会抛出类为 ArgumentCountError 的错误,就跟使用位置参数调用一样。
<?php
function makeyogurt($container = "bowl", $flavour)
{
return "Making a $container of $flavour yogurt.\n";
}
try
{
echo makeyogurt(flavour: "raspberry");
}
catch (Error $e)
{
echo get_class($e), ' - ', $e->getMessage(), "\n";
}
?>
以上示例在 PHP 8.0 中的输出:
Deprecated: Required parameter $flavour follows optional parameter $container in example.php on line 3 Making a bowl of raspberry yogurt.
以上示例在 PHP 8.1 中的输出:
Deprecated: Optional parameter $container declared before required parameter $flavour is implicitly treated as a required parameter in example.php on line 3 ArgumentCountError - makeyogurt(): Argument #1 ($container) not passed
返回类型与内部类的兼容性
大多数非 final 的内部方法现在要求重写方法声明一个可兼容的返回类型,否则在继承时会给出方法废弃的提示。如果由于 PHP 跨版本兼容性的问题,导致不能为重写方法声明返回类型,则可以添加 ReturnTypeWillChange 注解来取消废弃提示。
新的关键词
现在 readonly
是一个关键词。不过,它仍然可以被用作函数名。
never
现在是保留字,所以不能用于类,接口或者
trait,也禁止在命名空间中使用。
Resource 类型迁移为 Object 类型
一些 resource 类型已被迁移到 object 类型。要检查返回值,应该从 is_resource()
检查是否为资源,更改为检查返回值是否等于 false
。
-
现在 FTP 函数接收并返回 FTP\Connection 对象类型,而不是
ftp
resource 类型。 -
现在 IMAP 函数接收并返回 IMAP\Connection 对象类型,而不是
imap
resource 类型。 -
现在 LDAP 函数接收并返回 LDAP\Connection 对象类型,而不是
ldap link
resource 类型。 -
现在 LDAP 函数接收并返回 LDAP\Result 对象类型,而不是
ldap result
resource 类型。 -
现在 LDAP 函数接收并返回 LDAP\ResultEntry 对象类型,而不是
ldap result entry
resource 类型。 -
现在 PgSQL 函数接收并返回 PgSql\Connection 对象类型,而不是
pgsql link
resource 类型。 -
现在 PgSQL 函数接收并返回 PgSql\Result 对象类型,而不是
pgsql result
resource 类型。 -
现在 PgSQL 函数接收并返回 PgSql\Lob 对象类型,而不是
pgsql large object
resource 类型。 -
现在 PSpell 函数接收并返回 PSpell\Dictionary 对象类型,而不是
pspell
resource 类型。 -
现在 PSpell 函数接收并返回 PSpell\Config 对象类型,而不是
pspell config
resource 类型。
MySQLi
现在 mysqli_fetch_fields() 和 mysqli_fetch_field_direct() 对于 max_length
将返回 0
值。这一信息可以迭代结果集来计算,并获取最大长度。这是之前 PHP 内部的做法。
常量 MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH
不再生效。
常量 MYSQLI_STORE_RESULT_COPY_DATA
不再生效。传递给 mysqli::store_result()
的 mode
参数的所有值不再生效。
现在 mysqli::connect() 成功时返回 true
而不再返回 null
。
默认错误处理模式已经由 silent 变成了 exception,更多详情及如何设置该属性请参见 MySQLi
报告模式。要恢复之前的行为习惯,请使用:mysqli_report(MYSQLI_REPORT_OFF);
现在,扩展 mysqli_stmt::execute() 类需要指定额外的可选参数。
MySQLnd
mysqlnd.fetch_data_copy INI 指令已被取消。这不会造成用户可见的变化。
OpenSSL
现在 EC 私钥将以 PKCS#8 格式导出,而非像其他秘钥那样的传统格式。
现在 openssl_pkcs7_encrypt() 和 openssl_cms_encrypt() 将默认使用 AES-128-CBC,而非 RC2-40。RC2-40 加密被认为是不安全的,OpenSSL 3 默认不启用。
PHP 数据对象
现在 PDO::ATTR_STRINGIFY_FETCHES
的类型从 bool 变成了字符串 "0"
或
"1"
。之前的 bool 类型没有被字符串化。
现在当 PDO::ATTR_STRINGIFY_FETCHES
未启用时,以 PDO::PARAM_LOB
为参数调用
PDOStatement::bindColumn() 结果将始终绑定流。以前,结果是流或字符串,这取决于所用的数据库驱动及其执行绑定的时间。
MySQL 驱动
现在,当使用模拟预处理时,结果集里面的整数及浮点数将会以 PHP 原始类型返回,而不是字符串。这与原生的预处理方式一样。之前的行为方式可以通过
PDO::ATTR_STRINGIFY_FETCHES
恢复。
SQLite 驱动
现在,结果集中的整数及浮点数将会以 PHP 原始类型返回。之前的行为方式可以通过 PDO::ATTR_STRINGIFY_FETCHES
恢复。
Phar
为了遵守 ArrayAccess 接口,Phar::offsetUnset() 和 PharData::offsetUnset() 不再以 bool 类型返回。
常规
version_compare() 函数不再接收未经记录的操作符缩写。
现在 htmlspecialchars()、htmlentities()、htmlspecialchars_decode()、html_entity_decode()、get_html_translation_table()
使用 ENT_QUOTES | ENT_SUBSTITUTE
作为默认值,而不再是 ENT_COMPAT
。这意味着
'
被转义为 '
而不像之前那样不作处理。此外,有缺陷的
UTF-8 将被 Unicode 替代字符(substitute character)替换,而不是产生一个空字符串。
现在 debug_zval_dump() 函数可以打印封装的引用计数了,不仅仅只是打印 &
引用计数的值。这更准确地模拟了自 PHP 7.0 以来的引用注解。
现在 debug_zval_dump() 可打印 interned
字符串,而不是 interned 字符串和不可变数组的虚拟的引用计数。
PHP 标准库(SPL)
SplFixedArray 将会像 array 类型一样被 JSON 编码。
用户贡献的备注
备份地址:http://www.lvesu.com/blog/php/migration81.incompatible.php