数字与非数字形式的字符串之间的非严格比较现在将首先将数字转为字符串,然后比较这两个字符串。
数字与数字形式的字符串之间的比较仍然像之前那样进行。
请注意,这意味着 0 == "not-a-number"
现在将被认为是 false 。
比较 | 之前 | 之后 |
---|---|---|
0 == "0" |
true |
true |
0 == "0.0" |
true |
true |
0 == "foo" |
true |
false |
0 == "" |
true |
false |
42 == " 42" |
true |
true |
42 == "42foo" |
true |
false |
match
现在是一个保留字。
断言(Assertion)失败现在默认抛出异常。如果想要改回之前的行为,可以在 INI 设置中设置
assert.exception=0
。
mixed
现在是保留字,所以不能用于类,接口或者
trait,也禁止在命名空间中使用。
与类名相同的方法名将不再被当做构造方法。应该使用 __construct() 来取代它。
不再允许通过静态调用的方式去调用非静态方法。因此 is_callable() 在检查一个类名与非静态方法时将返回失败(应当检查一个类的实例)。
(real)
和 (unset)
转换已被移除。
移除 track_errors 执行。这意味着不能再用 php_errormsg。可以改用 error_get_last() 函数。
移除使用 __autoload() 函数指定自动加载器的功能。应该改用 spl_autoload_register()。
errcontext
参数将不再传递给使用 set_error_handler() 设置的自定义错误处理程序。
移除 create_function()。应该改用匿名函数。
移除 each()。应该改用 foreach 或者 ArrayIterator。
移除在方法中使用 Closure::fromCallable() 或 ReflectionMethod::getClosure() 创建的匿名函数中解绑 this 的能力。
移除了从包含 this 使用的正常闭包中解绑 this 的能力。
移除对对象使用 array_key_exists() 的能力。应该改用 isset() 或 property_exists()。
array_key_exists() 中 key
参数类型的行为已经和 isset() 和正常数组访问一致。所有的
key 类型现在使用通用的强制转换,数组/对象 key 会抛出 TypeError。
任意一个数组,将数字 n 作为第一个数字 key,下一个隐式键将会是 n+1。即使 n 为负数也是如此。
error_reporting 默认级别现在是 E_ALL
。之前排除 E_NOTICE
和 E_DEPRECATED
。
现在默认启用 display_startup_errors。
在没有父级的类中使用 parent 将会导致 fatal compile-time 错误。
@
操作将不再屏蔽 fatal
错误(E_ERROR
、E_CORE_ERROR
、E_COMPILE_ERROR
、E_USER_ERROR
、E_RECOVERABLE_ERROR
、E_PARSE
)。当使用
@
时,接受 error_reporting 为 0
的错误处理程序,应该调整为使用位掩码检查:
<?php
// 之前
function my_error_handler($err_no, $err_msg, $filename, $linenum) {
if (error_reporting() == 0) {
return false;
}
// ...
}
// 现在
function my_error_handler($err_no, $err_msg, $filename, $linenum) {
if (!(error_reporting() & $err_no)) {
return false;
}
// ...
}
?>
此外,应注意在生产环境中不显示错误消息,这可能会导致信息泄露。确保 display_errors=Off
与错误记录一起使用。
#[
不再解释为注释的开头,因为此语法现在用于注解。
由于不兼容的方法签名(违反 LSP)导致的继承错误现在将始终生成致命错误。以前在某些情况下会生成警告。
相对于位移、加法还有减法,连接运算符的优先级已经更改。
<?php
echo "Sum: " . $a + $b;
// 之前解释为:
echo ("Sum: " . $a) + $b;
// 现在解释为:
echo "Sum:" . ($a + $b);
?>
在运行时默认值解析为 null
的参数,将不在默默将参数类型标记为可为 null。必须改用指定可为 null 类型或者默认值为 null
。
<?php
// 之前:
function test(int $arg = CONST_RESOLVING_TO_NULL) {}
// 之后:
function test(?int $arg = CONST_RESOLVING_TO_NULL) {}
// 或者是
function test(int $arg = null) {}
?>
一些警告已转换为 Error 异常:
一些通知已转换为警告:
尝试将多字节字符串分配给字符串 offset 现在将发出警告。
源文件中的异常字符(比如字符串边界外的 NUL 字节)现在将导致 ParseError 异常而不是编译警告。
未捕获异常现在会经过“clean shutdown”,这意味着未捕获的异常之后调用析构方法。
编译时 fatal error“Only variables can be passed by reference”已延迟到运行时,并转换为“Argument cannot be passed by reference”Error 异常。
一些“Only variables should be passed by reference”通知已转换为“Argument cannot be passed by reference”异常。
匿名类生成的名称已经发生了改变。现在生成的名称将包括第一个父类或接口的名称:
<?php
new class extends ParentClass {};
// -> ParentClass@anonymous
new class implements FirstInterface, SecondInterface {};
// -> FirstInterface@anonymous
new class {};
// -> class@anonymous
?>
上面显示的名称仍然后跟 NUL 字节和唯一的后缀。
trait 别名适配中的非绝对 trait 方法引用现在必须明确:
<?php
class X {
use T1, T2 {
func as otherFunc;
}
function func() {}
}
?>
如果同时存在 T1::func()
和 T2::func()
,以前此代码会默默接受,并且 func 指向
T1::func
。现在则会生成 fatal error,必须明确编写 T1::func
or T2::func
。
trait 中定义的 abstract 方法签名现在会检查类中实现的方法:
<?php
trait MyTrait {
abstract private function neededByTrait(): string;
}
class MyClass {
use MyTrait;
// 错误,因为返回类型不匹配。
private function neededByTrait(): int { return 42; }
}
?>
现在将禁用的函数视为不存在的函数,调用禁用函数将报告未知,并且现在可以重新定义已禁用的函数。
data://
流封装协议不在可写,这与文档中的行为相匹配。
算术和位操作符 +
、-
、*
、/
、**
、%
、<<
、>>
、&
、|
、^
、~
、++
、--
的其中一个操作符是 array、resource 或非重载 object 时,现在将始终抛出
TypeError。唯一的例外是仍然支持 array +
array 的合并操作。
浮点数到字符串的强制转换现在始终不会受到独立 locale 的影响。
<?php
setlocale(LC_ALL, "de_DE");
$f = 3.14;
echo $f, "\n";
// Previously: 3,14
// Now: 3.14
?>
参阅 printf()、number_format() 和 NumberFormatter() 了解自定义数字格式的方法。
已经移除对使用大括号(花括号)进行偏移量访问的弃用支持。
<?php
// 将:
$array{0};
$array{"key"};
// 改为:
$array[0];
$array["key"];
?>
在私有方法上应用 final 修饰符现在将产生警告,除非该方法是构造方法。
如果对象的构造方法 exit(),那么将不再调用对象的析构方法,这与构造方法抛出异常时的行为相匹配。
命名空间名不能再包含空格:Foo\Bar
将识别为命名空间名称,而 Foo \ Bar
则不能。相反,保留关键字现在允许作为命名空间片段,这可能也会改变代码的解释:new\x
现在与
constant('new\x')
相同,而不是 new \x()
。
嵌套的三元表达式现在需要的括号。
debug_backtrace() 和 Exception::getTrace() 将不再提供对参数的引用。通过回溯将不可能更改函数参数。
数字字符串的处理方式已经更改,以便更直观和更少出错。现在允许在数字字符串中使用尾随空格,以便与起始空格的处理方式保持一致。这主要影响:
“前置数字字符串”的概念已删除大部分;仍然存在的目的是为了简化迁移。发出 E_NOTICE
“A non well-formed numeric value
encountered”的字符串现在将发出 E_WARNING
“A non-numeric value encountered”,并且所有发出
E_WARNING
“A non-numeric value encountered”的字符串现在将抛出 TypeError。这主要会影响:
E_WARNING
到 TypeError 的变更也影响了 E_WARNING
“Illegal string
offset 'string'”的非法字符串偏移。从字符串到 int/float 的明确强制转换的行为没有改变。
如果魔术方法声明了参数和返回类型,那么它们现在将会检查这些。签名应该与以下列表匹配:
__call(string $name, array $arguments): mixed
__callStatic(string $name, array $arguments): mixed
__clone(): void
__debugInfo(): ?array
__get(string $name): mixed
__invoke(mixed $arguments): mixed
__isset(string $name): bool
__serialize(): array
__set(string $name, mixed $value): void
__set_state(array $properties): object
__sleep(): array
__unserialize(array $data): void
__unset(string $name): void
__wakeup(): void
call_user_func_array() 数组的键现在将解释为参数名,而不是默默忽略。
不再允许在命名空间内声明名为 assert()
的函数,并发出 E_COMPILE_ERROR
。assert()
函数受引擎的特殊处理,当定义具有相同名称的命名空间函数时,可能会导致不一致的行为。
一些 resource 已经迁移到了 object。返回值检测从使用 is_resource() 替换为是否是 false
。
curl_init() 现在将返回 CurlHandle 对象而不是 resource。curl_close() 函数不再有作用,相反,如果不再引用,CurlHandle 实例将自动销毁。
curl_multi_init() 现在将返回 CurlMultiHandle 对象而不是 resource。curl_multi_close() 函数不再有作用,相反,如果不再引用,CurlMultiHandle 实例将自动销毁。
curl_share_init() 现在将返回 CurlShareHandle 对象而不是 resource。curl_share_close() 函数不再有作用,相反,如果不再引用,CurlShareHandle 实例将自动销毁。
enchant_broker_init() 现在将返回 EnchantBroker 对象而不是 resource。
enchant_broker_request_dict() 和 enchant_broker_request_pwl_dict() 现在将返回 EnchantDictionary 对象而不是 resource。
GD 扩展现在使用 GdImage 对象作为图像的底层数据结构,而不是 resource。imagedestroy() 函数不再有作用,相反,如果不再引用,GdImage 实例将自动销毁。
openssl_x509_read() 和 openssl_csr_sign() 现在将返回 OpenSSLCertificate 对象而不是 resource。弃用 openssl_x509_free() 函数且不再起作用,相反,如果不再引用,OpenSSLCertificate 实例将自动销毁。
openssl_csr_new() 现在将返回 OpenSSLCertificateSigningRequest 对象而不是 resource。
openssl_pkey_new() 现在将返回 OpenSSLAsymmetricKey 对象而不是 resource。弃用 openssl_pkey_free() 函数且不再起作用,相反,如果不再引用,OpenSSLAsymmetricKey 实例将自动销毁。
shmop_open() 现在将返回 Shmop 对象而不是 resource。弃用 shmop_close() 函数且不再起作用,相反,如果不再引用,Shmop 实例将自动销毁。
socket_create()、socket_create_listen()、socket_accept()、socket_import_stream()、socket_addrinfo_connect()、socket_addrinfo_bind() 和 socket_wsaprotocol_info_import() 现在将返回 Socket 对象而不是 resource。socket_addrinfo_lookup() 现在将返回 AddressInfo 对象组成的数组,而不是 resource。
msg_get_queue() 现在将返回 SysvMessageQueue 对象而不是 resource。
sem_get() 现在将返回 SysvSemaphore 对象而不是 resource。
shm_attach() 现在将返回 SysvSharedMemory 对象而不是 resource。
xml_parser_create() 和 xml_parser_create_ns() 现在将返回 XMLParser 对象而不是 resource。xml_parser_free() 函数不再有作用,相反,如果不再引用,XmlParser 实例将自动销毁。
inflate_init() 现在将返回 InflateContext 对象而不是 resource。
deflate_init() 现在将返回 DeflateContext 对象而不是 resource。
移除从类型库导入不区分大小写常量的功能。com_load_typelib() 的第二个参数不再是 false;不再禁用 com.autoregister_casesensitive;忽略 com.typelib_file 中的不区分大小写标记。
CURLOPT_POSTFIELDS
不再接受对象作为数组。要将对象解释为数组,手动执行 (array)
转换。这同样适用于接受数组的其它选项。
mktime() 和 gmmktime() 现在强制需要至少一个参数。time() 可以用来获取当前时间戳。
已移除 DOM 扩展中无行为和包含测试数据的的未实现类。这些类也已在最新版本的 DOM 标准中移除:
已移除 DOM 扩展中没有实现行为的方法:
已移除 read_exif_data();应该使用 exif_read_data() 替代。
已移除 FILTER_VALIDATE_URL
过滤中的 FILTER_FLAG_SCHEME_REQUIRED
和
FILTER_FLAG_HOST_REQUIRED
flag。scheme
和 host
始终(并且一直)必需。
filter_input() 等函数的 INPUT_REQUEST
和 INPUT_SESSION
源码已经移除。这些从未实现过,并且使用它们将始终生成警告。
移除弃用函数 image2wbmp()。
移除弃用函数 png2wbmp() 和 jpeg2wbmp()。
imagecropauto() 的 mode
参数默认不再接受
-1
。而是应该使用 IMG_CROP_DEFAULT
。
Windows 上,php_gd2.dll 已经重命名为 php_gd.dll。
已经移除 gmp_random()。应该使用 gmp_random_range() 或 gmp_random_bits()。
不再支持在发生错误时没有正确设置 errno 的 iconv 实现。
imap_headerinfo() 已移除未使用的 default_host
参数。
已移除 imap_headerinfo() 的别名函数 imap_header()。
已移除弃用常量 INTL_IDNA_VARIANT_2003
。
移除弃用常量 Normalizer::NONE
。
移除弃用函数 ldap_sort()、ldap_control_paged_result() 和 ldap_control_paged_result_response()。
ldap_set_rebind_proc() 的接口已修改;callback
不再接受空字符串;应该使用 null
代替。
已移除 mbstring.func_overload 指令。与其相关的
MB_OVERLOAD_MAIL
、MB_OVERLOAD_STRING
和 MB_OVERLOAD_REGEX
常量也已移除。最后,mb_get_info() 中的 "func_overload"
和
"func_overload_list"
条目也已移除。
使用 mb_parse_str() 时必须指定结果数组。
一些弃用的的 mbregex 别名已移除。请参阅下面的列表,以了解应该使用哪些函数:
mb_ereg_replace() 已移除 e
修饰符。应该使用 mb_ereg_replace_callback() 代替。
mb_ereg_replace() 的非字符串模式参数现在将解释为字符串而不是 ASCII 码点。可以通过调用 chr() 来恢复以前的行为。
mb_strpos()、mb_strrpos()、mb_stripos()、mb_strripos()、mb_strstr()、mb_stristr()、mb_strrchr()
和 mb_strrichr() 的 needle
参数现在可以为空。
已移除 mb_decode_numericentity() 内部不使用的 is_hex
参数。
mb_strrpos() 函数的第三个参数传递编码而不是偏移量的遗留行为已经移除;应该将带编码的 0
偏移量作为第四个参数提供。
ISO_8859-*
字符编码的别名已替换为 ISO8859-*
别名,以便与 iconv 扩展实现更好的互操作性。带下划线的 mbregex ISO 8859
别名(ISO_8859_*
和 ISO8859_*
)也已移除。
mb_ereg() 和 mb_eregi() 现在将在匹配成功时返回布尔值 true
。之前,如果未传递
matches
,则返回整数 1
;如果传递了 matches
,则返回
max(1, strlen($matches[0]))
。
OCI-Lob 类现在叫做 OCILob,OCI-Collection 类现在叫做 OCICollection,以实现 PHP 8 arginfo 类型注释工具强制执行的名称合规。
多个别名函数已标记为已弃用。
odbc_connect() 不再重用连接。
odbc_exec() 未使用的 flags
参数已移除。
openssl_seal() 和 openssl_open() 现在需要传递 method
,现在认为之前的
"RC4"
默认值不安全。
当传递无效的转义序列时,将不再解释为文字。此行为之前需要 X
修饰符——现在已忽略。
默认错误处理模式已经从“silent”变更为“exceptions”。参阅错误和错误处理获取详情。
一些 PDO 方法的签名已更改:
PDO::query(string $query, ?int $fetchMode = null, mixed ...$fetchModeArgs)
PDOStatement::setFetchMode(int $mode, mixed ...$args)
php.ini 指令 pdo_odbc.db2_instance_name 已移除。
PDO::inTransaction() 现在报告连接的实际事务状态,而不是 PDO
维护的近似状态。如果执行的是“隐式事务”查询,PDO::inTransaction() 将会随后返回
false
,因为事务不再活动状态。
弃用的 pg_connect() 使用多个参数的语法不再支持,而是使用连接字符串。
弃用的 pg_lo_import() 和 pg_lo_export() 将 connection 作为最后一个参数传递的签名不再支持。应该将 connection 作为第一个参数传递。
pg_fetch_all() 对于 0 条记录的结果集,现在将返回空数组而不是 false
。
与 phar 关联的元数据将不再自动反序列化,以修复由于对象实例化、自动加载等导致的潜在安全漏洞。
方法签名
ReflectionClass::newInstance($args)
ReflectionFunction::invoke($args)
ReflectionMethod::invoke($object, $args)
已变更为:
ReflectionClass::newInstance(...$args)
ReflectionFunction::invoke(...$args)
ReflectionMethod::invoke($object, ...$args)
必须同时兼容 PHP 7 和 PHP 8 的代码可以使用以下签名来兼容这两个版本:
ReflectionClass::newInstance($arg = null, ...$args)
ReflectionFunction::invoke($arg = null, ...$args)
ReflectionMethod::invoke($object, $arg = null, ...$args)
ReflectionType::__toString() 方法现在将返回该类型的完整调试表示,并且不再弃用。特别是,结果将包括可空类型的可空性指示符。返回值的格式不稳定,并且可能在不同 PHP 版本之间发生变化。
Reflection export() 方法已经移除。相反,反射对象可以转换为字符串。
ReflectionMethod::isConstructor() 和 ReflectionMethod::isDestructor()
现在也为接口的 __construct() 和 __destruct()
方法返回 true
。之前只用于类方法和 trait。
ReflectionType::isBuiltin() 方法已移至 ReflectionNamedType。ReflectionUnionType 没有。
socket_addrinfo_lookup() 弃用的 AI_IDN_ALLOW_UNASSIGNED
和
AI_IDN_USE_STD3_ASCII_RULES
flags
已移除。
SplFileObject::seek() 总是寻找到一行的开头。之前,位置 >=1
会搜索到下一行的开头。
SplHeap::compare() 现在指定方法签名。实现此方法的继承类现在必须使用兼容的方法签名。
SplDoublyLinkedList::push()、SplDoublyLinkedList::unshift() 和
SplQueue::enqueue() 现在返回 void 而不是 true
。
spl_autoload_register() 现在将始终对无效参数抛出 TypeError,因此将会忽略第二个参数
do_throw
,并且如果将其设置为 false
,则会发出 notice。
SplFixedArray 现在是 IteratorAggregate 而不是 Iterator。SplFixedArray::rewind()、SplFixedArray::current()、SplFixedArray::key()、SplFixedArray::next() 和 SplFixedArray::valid() 已移除。在其位置上新增了 SplFixedArray::getIterator()。现在任何在 SplFixedArray 上迭代的代码都必须通过 SplFixedArray::getIterator() 获取 Iterator。这意味着 SplFixedArray 现在可以安全地在嵌套循环中使用。
assert() 将不再执行字符串参数,而是像其他参数一样对待它们。应该使用 assert($a == $b)
而不是 assert('$a == $b')
。assert.quiet_eval ini 指令和 ASSERT_QUIET_EVAL
常量也已移除,因为不再有任何效果。
如果不指定 result 数组,则无法再使用 parse_str()。
string.strip_tags 过滤器已移除。
strpos()、strrpos()、stripos()、strripos()、strstr()、strchr()、strrchr()
和 stristr() 的 needle
参数将始终解释为字符串。非字符串的 needle 之前将解释为 ASCII 码点。现在手动调用 chr() 可用于恢复以前的行为。
strpos()、strrpos()、stripos()、strripos()、strstr()、stristr()
和 strrchr() 的 needle
参数现在可为空。
substr()、substr_count()、substr_compare() 和 iconv_substr() 的
length
参数现在可为 null
。null
值的行为就像是没有提供 length 参数,因此会返回字符串的剩余部分而不是空字符串。
array_splice() 的 length
参数现在可为 null
。null
值的行为跟忽略参数时相同,从而移除从偏移量到数组末尾的所有内容。
vsprintf()、vfprintf() 和 vprintf() 的 args
参数现在必须是数组。之前接受任何类型。
password_hash() 不再支持 'salt'
选项。如果使用 'salt'
选项则会生成 warning,提供的 salt
将会忽略,并使用生成的 slat 代替。
如果传递空字符串, quotemeta() 函数现在将返回空字符串。之前返回 false
。
下列函数将移除:
不再支持以相反的参数顺序 ($pieces, $glue)
调用 implode()。
parse_url() 现在将区分不存在或空的查询和片段:
http://example.com/foo → query = null, fragment = null
http://example.com/foo? → query = "", fragment = null
http://example.com/foo# → query = null, fragment = ""
http://example.com/foo?# → query = "", fragment = ""
null
。
var_dump() 和 debug_zval_dump() 现在将使用 serialize_precision 而不是 precision 来打印浮点数。在默认配置中,这意味着这些调试函数现在可以完全准确地打印浮点数。
如果 __sleep() 返回的数组包含不存在的属性,这些属性现在会默认忽略。之前会序列化这些属性,就好像它们的值为 null
一样。
启动时的默认区域设置现在始终为 "C"
。默认情况下,不会从环境中继承任何区域设置。之前,LC_ALL
设置为 "C"
,而
LC_CTYPE
是从环境中继承。但是,如果不手动调用 setlocale(),某些函数将不尊重继承的语言环境。如果应更改默认区域设置组件,现在始终需要手动调用
setlocale()。
已移除 crypt() 中已弃用的 DES 回退。如果将未知的 salt 格式传递给
crypt(),该函数将失败并返回 *0
,而不是立即回退到弱 DES 散列。
crypt() 现在指定超出 SHA256/SHA512 范围的 rounds 时将失败,返回
*0
,而不是修改为最接近的限制。这与 glibc 的行为相匹配。
如果数组包含比较后相等的元素,则排序函数的结果可能会发生改变。
如果使用带有引用参数的回调,则任何没有手动指定参数是引用的时候,接受该回调的函数都会发出 warn。示例包括 array_filter() 和 array_reduce()。以前大多数(但不是全部)函数都是这种情况。
file_get_contents() 等函数使用的 HTTP stream 封装协议现在默认使用 HTTP/1.1 而不是
HTTP/1.0。这不会改变客户端的行为,但可能会导致服务器做出不同的响应。要保留旧行为,请设置
'protocol_version'
stream 上下文选项,例如
<?php
$ctx = stream_context_create(['http' => ['protocol_version' => '1.0']]);
echo file_get_contents('http://example.org', false, $ctx);
?>
不再支持在没有指定 salt 时调用 crypt()。如果想使用自动生成的 salt 产出强散列,改用 password_hash()。
substr()、mb_substr()、iconv_substr() 和
grapheme_substr() 现在始终控制超出范围的 offset 控制到字符串的边界。在某些情况下,之前会返回
false
而不是空字符串。
在 Windows 上,使用 shell 的程序执行函数(proc_open()、exec()、popen())现在执行 %comspec% /s /c "$commandline",始终与执行 $commandline 效果相同 (没有额外的引号)。
sem_get() 的 auto_release
参数已从接受 int
更改为接受 bool。
从 tidy_repair_string() 中删除内部未使用的
use_include_path
参数。
tidy::repairString() 和 tidy::repairFile() 成为静态方法。
T_COMMENT
记号将不再包含尾随的换行符。换行符将成为以下 T_WHITESPACE
记号的一部分。需要注意的是,T_COMMENT
后面并不总是跟空格,也可能跟着
T_CLOSE_TAG
或者文件结尾。
namespace 名称现在使用 T_NAME_QUALIFIED
(Foo\Bar
)、T_NAME_FULLY_QUALIFIED
(\Foo\Bar
)
和 T_NAME_RELATIVE
(namespace\Foo\Bar
)记号表示。T_NS_SEPARATOR
仅用于独立 namespace
分隔符,仅与 group use 声明结合的有效语法。
XMLReader::open() 和 XMLReader::xml() 现在是静态方法。也可以作为实例方法调用,但如果继承类需要覆盖这些方法,要声明为 static。
XML-RPC 扩展已移动到 PECL,不再是 PHP 发行版的一部分。
ZipArchive::OPSYS_Z_CPM
已移除(名字错误)。使用
ZipArchive::OPSYS_CPM
代替。
gzgetss() 已移除。
zlib.output_compression 不再对
Content-Type: image/*
自动禁用。
测试运行器从 run-test.php 重命名为 run-tests.php,以匹配其在 php-src 中的名字。