## 不向后兼容的变更

### 当传递参数过少时将抛出错误

在过去如果我们调用一个用户定义的函数时，提供的参数不足，那么将会产生警告（warning）。现在，这个警告被提升为错误异常（Error exception）。这个变更仅对用户定义的函数生效，并不包含内置函数。例如：

    <?php
    function test($param){}
    test();

以上示例的输出类似于：

    Fatal error: Uncaught ArgumentCountError: Too few arguments to function test(), 0 passed in %s on line %d and exactly 1 expected in %s:%d

### 禁止动态调用作用域内的内省（introspection）函数

禁止动态调用（`$func()` 或 `array_map('extract', ...)` 的形式等）某些函数。这些函数会检查或修改另一个作用域，并呈现出不明确且不可靠的行为。函数如下：

- assert()——字符串作为第一个参数
- compact()
- extract()
- func_get_args()
- func_get_arg()
- func_num_args()
- get_defined_vars()
- mb_parse_str()——使用一个参数
- parse_str()——使用一个参数

    <?php
    (function () {
        $func = 'func_num_args';
        $func();
    })();

以上示例会输出：

    Warning: Cannot call func_num_args() dynamically in %s on line %d

### 无效的 class、interface 和 trait 名称

下列名称不能用于 class、interfaces 或 traits 名：

- void
- iterable

### 数字字符串转换现在遵循科学记数法

现在在数字字符串上执行整数运算和转换会考虑科学计数法。这还包括 `(int)` 类型转换操作以及以下函数：intval()（基数为 10）、settype()、decbin()、decoct() 和 dechex()。

### 修复 mt_rand() 算法

mt_rand() 现在默认使用修复版本的梅森旋转算法。如果依赖于 mt_rand() 的确定输出，则可以使用 `MT_RAND_PHP` 作为 mt_srand() 的可选第二个参数，以保留旧的（不正确的）实现。

### rand() 是 mt_rand() 的别名以及 srand() 是 mt_srand() 的别名

rand() 和 srand() 现已成为 mt_rand() 和 mt_srand() 的别名。这意味着以下函数已经更改：rand()、shuffle()、str_shuffle() 和 array_rand()。

### 禁止在标识符中使用 ASCII 删除控制字符

ASCII 删除控制字符（`0x7F`）不能用于未加引号的标识符中。

### `error_log` 更改为 `syslog` 值

如果 `error_log` ini 设置为 `syslog`，PHP 错误等级会映射到 syslog 错误级别。这在错误日志中带来了更好的区分，与之前相反，之前所有的错误只记录了错误级别。

### 在不完整的对象上不再调用析构方法

对于在执行构造方法时抛出异常的对象，现在析构方法绝不会被调用。在先前的版本中，这个行为取决于对象是否在构造方法以外的地方呗引用（例如一个错误堆栈回溯）

### call_user_func() 不再支持对传址的函数的调用

call_user_func() 现在在调用一个以引用作为参数的函数时将始终产生一个警告。先前这取决于这个调用行为是否完全符合条件。

此外，call_user_func() 和 call_user_func_array() 在这种情况下将不再中断函数调用。现在会出现包含“expected reference”的警告信息，但函数调用将正常进行。

### 字符串不再支持空索引操作符

对字符串使用一个空索引操作符（例如`$str[] = $x`）将会抛出一个致命错误，而不是静默地将其转为一个数组。

### ini 配置项移除

下列 ini 配置项已经被移除：

- `session.entropy_file`
- `session.entropy_length`
- `session.hash_function`
- `session.hash_bits_per_character`

### 在引用赋值期间自动创建元素时的数组排序已更改

当通过引用赋值自动创建这些元素时，数组中元素的顺序就会发生变化。例如：

    <?php
    $array = [];
    $array["a"] =& $array["b"];
    $array["b"] = 1;
    var_dump($array);
    ?>

以上示例在 PHP 7.0 中的输出：

    array(2) {
      ["a"]=>
      &int(1)
      ["b"]=>
      &int(1)
    }

以上示例在 PHP 7.1 中的输出：

    array(2) {
      ["b"]=>
      &int(1)
      ["a"]=>
      &int(1)
    }

### 相等元素的排序顺序

内部排序算法已得到改进，这可能会导致元素比较相等的排序顺序与以前不同。

> 注意:

> 不要依赖比较相等的元素的顺序；它可能随时改变。

### E_RECOVERABLE 错误的错误消息

E_RECOVERABLE 错误的错误消息已从“可捕获的致命错误”更改为“可恢复的致命错误”。

### unserialize() 的 $options 参数

unserialize() 的 $options 参数的 `allowed_classes` 元素现在是严格类型，也就是说，如果指定了 array 或 bool 以外的任何内容，则 unserialize() 返回 `false` 并发出 `E_WARNING`。

### DateTime 构造方法包含微秒

DateTime 和 DateTimeImmutable 现在构造当前时间时正确地包含微秒，无论是明确指定的还是使用相对字符串（例如 `"first day of next month"`）。这意味着两个新创建的实例的原生比较现在更有可能返回 `false` 而不是 `true`：

    <?php
    new DateTime() == new DateTime();
    ?>

### 核心错误转换为 Error 异常

在 Date 扩展中，DateTime 或 DatePeriod 类的无效序列化数据或者序列化数据的时区初始化失败，现在将从 __wakeup() 或 __set_state() 方法抛出 Error 异常，而不是导致致命错误。

在 DBA 扩展中，如果键没有完全包含两个元素，数据修改函数（例如 dba_insert()）现在将抛出 Error 异常，而不是触发可捕获的致命错误。

在 DOM 扩展中，无效的模式或 RelaxNG 验证上下文现在将引发 Error 异常，而不是导致致命错误。同样，尝试注册不继承适宜基类的节点类、尝试读取无效属性或写入只读属性，现在也将引发 Error 异常。

在 IMAP 扩展中，长度超过 16385 字节的电子邮件地址将引发 Error 异常，而不是导致致命错误。

在 Intl 扩展中，在调用父级方法之前，在继承 Collator 的类中调用父级构造方法失败，现在将抛出 Error 而不是可恢复的致命错误。此外克隆 Transliterator 对象时，如果无法克隆内部 transliterator，将抛出 Error 异常，而不会导致致命错误。

在 LDAP 扩展中，向 ldap_batch_modify() 提供未知的修改类型现在将引发 Error 异常，而不是导致致命错误。

在 mbstring 扩展中，如果提供了无效的 PHP 表达式并且使用了“e”选项，mb_ereg() 和 mb_eregi() 函数现在将引发 ParseError 异常。

在 Mcrypt 扩展中，如果 mcrypt 无法初始化，mcrypt_encrypt() 和 mcrypt_decrypt() 现在将抛出 Error 异常，而不是导致致命错误。

在 mysqli 扩展中，尝试读取无效属性或写入只读属性现在将引发 Error 异常，而不是导致致命错误。

在反射扩展中，检索 reflection 对象或检索对象属性失败现在将引发 Error 异常，而不是导致致命错误。

在 Session 扩展中，当调用必须生成会话 ID 的函数时，自定义会话处理程序不返回字符串格式的会话 ID 现在将引发 Error 异常，而不是导致致命错误。

在 SimpleXML 扩展中，创建未命名或重复的属性现在将引发 Error 异常，而不是导致致命错误。

在 SPL 扩展中，尝试克隆 SplDirectory 对象现在将引发 Error 异常，而不是导致致命错误。同理，在迭代对象时调用 ArrayIterator::append() 现在也会引发 Error 异常。

在标准扩展中，将字符串作为其第一个参数时，assert() 函数现在将抛出 ParseError 异常，而不是在 PHP 代码无效时导致可捕获的致命错误。同理，在类作用域之外调用 forward_static_call() 现在将引发 Error 异常。

在 Tidy 扩展中，手动创建 tidyNode 现在将抛出 Error 异常，而不是导致致命错误。

在 WDDX 扩展中，序列化时的循环引用现在将引发 Error 异常，而不是导致致命错误。

在 XML-RPC 扩展中，序列化时的循环引用现在将抛出 Error 异常实例，而不是导致致命错误。

在 Zip 扩展中，如果 glob 支持无效，ZipArchive::addGlob() 方法现在将引发 Error 异常，而不是导致致命错误。

### 词法绑定变量不能重用名字

通过 `use` 构造绑定到 closure 的变量不能使用与任何 superglobals、$this 或任何参数相同的名称。例如，所有这些函数定义都会导致致命错误：

    <?php
    $f = function () use ($_SERVER) {};
    $f = function () use ($this) {};
    $f = function ($param) use ($param) {};

### long2ip() 参数类型更改

long2ip() 现在接受 int 而不是 string。

### JSON 编/解码

`serialize_precision` ini 设置现在控制编码 float 时的序列化精度。

解码空键（empty key）现在会产生空属性，而不是 `_empty_` 作为属性名称。

    <?php
    var_dump(json_decode(json_encode(['' => 1])));

以上示例的输出类似于：

    object(stdClass)#1 (1) {
      [""]=>
      int(1)
    }

当向 json_encode() 提供 `JSON_UNESCAPED_UNICODE` flag 时，现在转义序列 U+2028 和 U+2029。

### 更改 mb_ereg() 和 mb_eregi() 参数语义

如果没有匹配到内容，mb_ereg() 和 mb_eregi() 函数（`regs`）的第三个参数现在将设置为空数组。以前，不会修改该参数。

### 放弃对 sslv2 stream 的支持

sslv2 stream 现已在 OpenSSL 中删除。

### 在编译时禁止 "return;" 用于类型化返回

在声明返回类型的函数中，没有参数的 return 语句现在触发 `E_COMPILE_ERROR`（除非返回类型声明为 void），即使永远不会到达 return 语句。

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open