# 补充\*不向后兼容的变更

## 目录:

* E\_STRICT 警告级别变更
* 关于list()处理方式的变更
  * 常用的方式
  * list() 不再以反向的顺序来进行赋值
  * 空的list()赋值支持已经被移除
  * list() string 不再能解开
* 当引用分配时自动创建元素的数组排序已更改
* *global*只接受简单变量
* 非**Traversable**对象的遍历(本文无座介绍,详见[链接](http://php.net/manual/zh/migration70.incompatible.php) , 搜索"非**Traversable**对象的遍历")
* 函数参数附近的括号不再影响行为
* foreach的变化
  * foreach不再改变内部数组指针
  * foreach通过值遍历时，操作的值为数组的副本
  * foreach通过引用遍历时，有更好的迭代特性
* string处理上的调整
  * 十六进制字符串不再被认为是数字
  * *\u{*&#x53EF;能引起错误
* 被移除的函数（Removed functions）
  * [call\_user\_method()](https://www.gitbook.com/book/xiaoxiami/php-7/edit) 和 [call\_user\_method\_array()](https://www.gitbook.com/book/xiaoxiami/php-7/edit)
  * 所有的 ereg\* 函数
  * [mcrypt](https://www.gitbook.com/book/xiaoxiami/php-7/edit) 别名
  * 所有 ext/mysql 函数
  * [intl](https://www.gitbook.com/book/xiaoxiami/php-7/edit) 别名
  * set\_magic\_quotes\_runtime()
  * set\_socket\_blocking()
  * dl() in PHP-FPM
  * GD Type1 functions
* 被移除掉的 INI 配置指令
  * 被移除的功能
* 其他不向后兼容的变更
  * new 操作符创建的对象不能以引用方式赋值给变量
  * 无效的类、接口以及 trait 命名
  * 移除了 ASP 和 script PHP 标签
  * 从不匹配的上下文发起调用
  * yield 变更为右联接运算符
  * 函数定义不可以包含多个同名参数
  * Switch 语句不可以包含多个 default 块
  * 在函数中检视参数值会返回当前的值
  * $HTTP\_RAW\_POST\_DATA被移除
  * INI 文件中#注释格式被移除
  * JSON 扩展已经被 JSOND 取代
  * 在数值溢出的时候，内部函数将会失败
  * 自定义会话处理器的返回值修复
  * 相等的元素在排序时的顺序问题

## E\_STRICT 警告级别变更

原有的`E_STRICT`警告都被迁移到其他级别。`E_STRICT`常量会被保留，所以调用*error\_reporting(E\_ALL|E\_STRICT)*&#x4E0D;会引发错误.

举例(以静态方式调用实例方法):

```php
<?php
error_reporting(E_ALL|E_STRICT);
class mycls{

  function func()
  {
  echo "none static";
  }

}

mycls::func();
```

php7 中则会印发新的`E_DEPRECATED 级别的错误`

```
eprecated: Non-static method mycls::func() should not be called statically in xxxx
```

| **场景**                  | **新的级别/行为**    |
| ----------------------- | -------------- |
| 将资源类型的变量用作键来进行索引        | `E_NOTICE`     |
| 抽象静态方法                  | 不再警告，会引发错误     |
| 重复定义构造器函数               | 不再警告，会引发错误     |
| 在继承的时候，方法签名不匹配          | `E_WARNING`    |
| 在两个 trait 中包含相同的（兼容的）属性 | 不再警告，会引发错误     |
| 以非静态调用的方式访问静态属性         | `E_NOTICE`     |
| 变量应该以引用的方式赋值            | `E_NOTICE`     |
| 变量应该以引用的方式传递（到函数参数中）    | `E_NOTICE`     |
| 以静态方式调用实例方法             | `E_DEPRECATED` |

## 关于list()处理方式的变更

详见官方: [关于list()处理方式的变更 ](http://php.net/manual/zh/migration70.incompatible.php)

### 常用的方式:

```php
<?php
$str = "China|Chinese";

list($country, $language) = explode('|', $str);

echo 'country:' . $country;
echo 'language:' . $language;
```

### list() 不再以反向的顺序来进行赋值.

官方说明:

PHP7 现在会按照变量定义的顺序来给他们进行赋值，而非反过来的顺序。 通常来说，这只会影响list() 与数组的\[]操作符一起使用的案例，如下所示：

```php
<?php
list($a[], $a[], $a[]) = [1, 2, 3];
var_dump($a);
?>
```

Output of the above example in PHP 5:

```
array(3) {
  [0]=>
  int(3)
  [1]=>
  int(2)
  [2]=>
  int(1)
}
```

Output of the above example in PHP 7:

```
array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}
```

总之，我们推荐不要依赖[list()](http://php.net/manual/zh/function.list.php)的赋值顺序，因为这是一个在未来也许会变更的实现细节。

### 空的list () 赋值支持已经被移除

[list()](http://php.net/manual/zh/function.list.php)结构在PHP 7 现在不再能是空的。如下的例子不再被允许：

```php
<?php
list() = $a;
list(,,) = $a;
list($x, list(), $y) = $a;
?>
```

### **list() string 不再能解开**

如下代码,在php 5.x 当中顺利运行,并输出相应的 a b 值 ,但是在php7 中不会输出 如下:

```php
<?php
$str = 'ab';
list($a, $b) = $str;
echo $a;
echo $b;
```

list() 不再能解开字符串（string）变量。 你可以使用str\_split()来代替它,如下代码:

> str\_split() 函数把字符串分割到数组中。 第二个可选参数支持规定每个数组元素的长度。默认是 1。

```php
<?php
$str = 'ab';
list($a, $b) = str_split($str);
echo $a;
echo $b;
```

## 当引用分配时自动创建元素的数组排序已更改

数组中的元素的顺序已更改，这些元素在引用引用赋值时自动创建。例如:

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

Output of the above example in PHP 5:

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

Output of the above example in PHP 7:

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

## *global*只接受简单变量

可变变量不再能够与 global 关键字一起使用。 如果在PHP7 中需要的话可以使用圆括号来模拟之前的行为。

```php
<?php
function f() {
    // Valid in PHP 5 only.
    global $$foo->bar;

    // Valid in PHP 5 and 7.
    global ${$foo->bar};
}
?>
```

作为一个通用的准则，[*global*](http://php.net/manual/zh/language.variables.scope.php#language.variables.scope.global)一个除了裸的变量以外的任何东西都是不被推荐的。

## 函数参数附近的括号不再影响行为

在PHP 7中(官方标注为php5,经过测试php5中无报错,报错在php7中,故作修改)，当函数参数通过引用传递时，围绕函数参数使用冗余括号可以保持严格的标准警告。警告将永远发出。

```php
<?php
error_reporting(E_ALL);
ini_set('display_errors', true);

function getArray() {
    return [1, 2, 3];
}

function squareArray(array &$a) {
    foreach ($a as &$v) {
        $v **= 2;
    }
}

// Generates a warning in PHP 7.
squareArray((getArray()));
```

以上栗子会报错:

```
Notice: Only variables should be passed by reference in xxxxx
```

## foreach的变化

foreach发生了细微的变化，控制结构， 主要围绕阵列的内部数组指针和迭代处理的修改。

### foreach不再改变内部数组指针

在PHP7之前，当数组通过foreach迭代时，数组指针会移动。现在开始，不再如此，见下面代码:

```php
<?php
$array = [0, 1, 2];
foreach ($array as &$val) {
    var_dump(current($array));
}
?>
```

Output of the above example in PHP 5:

```
int(1)
int(2)
bool(false)
```

Output of the above example in PHP 7:

```
int(0)
int(0)
int(0)
```

### foreach通过值遍历时，操作的值为数组的副本

当默认使用通过值遍历数组时，foreach实际操作的是数组的迭代副本，而非数组本身。这就意味着，foreach 中的操作不会修改原数组的值。

### foreach通过引用遍历时，有更好的迭代特性

当使用引用遍历数组时，现在foreach在迭代中能更好的跟踪变化。例如，在迭代中添加一个迭代值到数组中，参考下面的代码：

```php
<?php
$array = [0];
foreach ($array as &$val) {
    var_dump($val);
    $array[1] = 1;
}
?>
```

Output of the above example in PHP 5:

```
int(0)
```

Output of the above example in PHP 7:

```
int(0)
int(1)
```

## string处理上的调整

### 十六进制字符串不再被认为是数字

含十六进制字符串不再被认为是数字(**也就是十六进制的字符串不会转成十进制数字进行比较,而是做一个字符串**)。例如：

```php
<?php
var_dump("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));
?>
```

Output of the above example in PHP 5:

```
bool(true)
bool(true)
int(15)
string(2) "oo"
```

Output of the above example in PHP 7:

```
bool(false)
bool(false)
int(0)

Notice: A non well formed numeric value encountered in /tmp/test.php on line 5
string(3) "foo"
```

解决办法:

filter\_var() 函数可以用于检查一个 string 是否含有十六进制数字,并将其转换为integer:

```php
<?php
$str = "0xffff";
$int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
if (false === $int) {
    throw new Exception("Invalid integer!");
}
var_dump($int); // int(65535)
?>
```

### *\u{*&#x53EF;能引起错误

由于新的[Unicode codepoint escape syntax](http://php.net/manual/zh/migration70.new-features.php#migration70.new-features.unicode-codepoint-escape-syntax) 语法， 紧连着无效序列并包含`\u{`的字串可能引起致命错误。 为了避免这一报错，应该避免反斜杠开头。

## 被移除的函数（Removed functions）

### [call\_user\_method()](http://php.net/manual/zh/function.call-user-method.php) 和 [call\_user\_method\_array()](http://php.net/manual/zh/function.call-user-method-array.php)

这两个函数从PHP 4.1.0开始被废弃，应该使用[call\_user\_func()](http://php.net/manual/zh/function.call-user-func.php)和[call\_user\_func\_array()](http://php.net/manual/zh/function.call-user-func-array.php)。 你也可以考虑使用[变量函数](http://php.net/manual/zh/functions.variable-functions.php)或者[*...*](http://php.net/manual/zh/functions.arguments.php#functions.variable-arg-list.new)操作符。

### 所有的 ereg\* 函数

所有[ereg](http://php.net/manual/zh/book.regex.php)系列函数被删掉了。[PCRE](http://php.net/manual/zh/book.pcre.php)作为推荐的替代品。

### [mcrypt](http://php.net/manual/zh/book.mcrypt.php)别名

已废弃的[mcrypt\_generic\_end()](http://php.net/manual/zh/function.mcrypt-generic-end.php)函数已被移除，请使用[mcrypt\_generic\_deinit()](http://php.net/manual/zh/function.mcrypt-generic-deinit.php)代替。

此外，已废弃的[mcrypt\_ecb()](http://php.net/manual/zh/function.mcrypt-ecb.php),[mcrypt\_cbc()](http://php.net/manual/zh/function.mcrypt-cbc.php),[mcrypt\_cfb()](http://php.net/manual/zh/function.mcrypt-cfb.php)和[mcrypt\_ofb()](http://php.net/manual/zh/function.mcrypt-ofb.php)函数已被移除，请配合恰当的`MCRYPT_MODE_*`常量来使用[mcrypt\_decrypt()](http://php.net/manual/zh/function.mcrypt-decrypt.php)进行代替。

### 所有 ext/mysql 函数

所有[ext/mysql](http://php.net/manual/zh/book.mysql.php)函数已被删掉了。 如何选择不同的 MySQL API，详情请见[选择 MySQL API](http://php.net/manual/zh/mysqlinfo.api.choosing.php)。

### 所有 ext/mssql 函数

所有[ext/mssql](http://php.net/manual/zh/book.mssql.php)函数已被删掉了。 替代品的列表，参见[MSSQL 介绍](http://php.net/manual/zh/intro.mssql.php)。

### [intl](http://php.net/manual/zh/book.intl.php)别名

已废弃的[datefmt\_set\_timezone\_id()](http://php.net/manual/zh/intldateformatter.settimezoneid.php)和[IntlDateFormatter::setTimeZoneID()](http://php.net/manual/zh/intldateformatter.settimezoneid.php)函数已被移除，请使用[datefmt\_set\_timezone()](http://php.net/manual/zh/intldateformatter.settimezone.php)与[IntlDateFormatter::setTimeZone()](http://php.net/manual/zh/intldateformatter.settimezone.php)代替。

### [set\_magic\_quotes\_runtime()](http://php.net/manual/zh/function.set-magic-quotes-runtime.php)

[set\_magic\_quotes\_runtime()](http://php.net/manual/zh/function.set-magic-quotes-runtime.php), 和它的别名[magic\_quotes\_runtime()](http://php.net/manual/zh/function.magic-quotes-runtime.php)已被移除. 它们在PHP 5.3.0中已经被废弃,并且 在[in PHP 5.4.0](http://php.net/manual/zh/migration54.incompatible.php)也由于魔术引号的废弃而失去功能。

### [set\_socket\_blocking()](http://php.net/manual/zh/function.set-socket-blocking.php)

已废弃的[set\_socket\_blocking()](http://php.net/manual/zh/function.set-socket-blocking.php)函数已被移除，请使用[stream\_set\_blocking()](http://php.net/manual/zh/function.stream-set-blocking.php)代替。

### [dl()](http://php.net/manual/zh/function.dl.php) in PHP-FPM

[dl()](http://php.net/manual/zh/function.dl.php)在 PHP-FPM 不再可用，在 CLI 和 embed SAPIs 中仍可用。

### [GD](http://php.net/manual/zh/book.image.php) Type1 functions

PostScript Type1字体的支持已经从GD扩展删除，导致以下功能的去除：

* [imagepsbbox()](http://php.net/manual/zh/function.imagepsbbox.php)
* [imagepsencodefont()](http://php.net/manual/zh/function.imagepsencodefont.php)
* [imagepsextendfont()](http://php.net/manual/zh/function.imagepsextendfont.php)
* [imagepsfreefont()](http://php.net/manual/zh/function.imagepsfreefont.php)
* [imagepsloadfont()](http://php.net/manual/zh/function.imagepsloadfont.php)
* [imagepsslantfont()](http://php.net/manual/zh/function.imagepsslantfont.php)
* [imagepstext()](http://php.net/manual/zh/function.imagepstext.php)

推荐使用 TrueType 字体和相关的函数作为替代。

## 被移除掉的 INI 配置指令

### 被移除的功能

以下 INI 配置指令已经被移除，同时移除的还有其对应的功能

* [`always_populate_raw_post_data`](http://php.net/manual/zh/ini.core.php#ini.always-populate-raw-post-data)
* [`asp_tags`](http://php.net/manual/zh/ini.core.php#ini.asp-tags)

`xsl.security_prefs`

`xsl.security_prefs`指令被移除 在预处理的时候，取而代之的方法[XsltProcessor::setSecurityPrefs()](http://php.net/manual/zh/xsltprocessor.setsecurityprefs.php)应该被调用到

## 其他不向后兼容的变更

### new 操作符创建的对象不能以引用方式赋值给变量

[*new*](http://php.net/manual/zh/language.oop5.basic.php#language.oop5.basic.new)语句创建的对象不能 以引用的方式赋值给变量。

```php
<?php
class C {}
$c =& new C;
?>
```

Output of the above example in PHP 5:

```php
Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3
```

Output of the above example in PHP 7:

```
Parse error: syntax error, unexpected 'new' (T_NEW) in /tmp/test.php on line 3
```

### 无效的类、接口以及 trait 命名

不能以下列名字来命名类、接口以及 trait：

* [bool](http://php.net/manual/zh/language.types.boolean.php)
* [int](http://php.net/manual/zh/language.types.integer.php)
* [float](http://php.net/manual/zh/language.types.float.php)
* [string](http://php.net/manual/zh/language.types.string.php)
* `NULL`
* `TRUE`
* `FALSE`

此外，也不要使用下列的名字来命名类、接口以及 trait。虽然在 PHP 7.0 中， 这并不会引发错误， 但是这些名字是保留给将来使用的。

* [resource](http://php.net/manual/zh/language.types.resource.php)
* [object](http://php.net/manual/zh/language.types.object.php)
* [mixed](http://php.net/manual/zh/language.pseudo-types.php#language.types.mixed)
* numeric

### 移除了 ASP 和 script PHP 标签

使用类似 ASP 的标签，以及 script 标签来区分 PHP 代码的方式被移除。 受到影响的标签有：

**被移除的 ASP 和 script 标签**

| 开标签                       | 闭标签         |
| ------------------------- | ----------- |
| `<%`                      | `%>`        |
| `<%=`                     | `%>`        |
| `<script language="php">` | `</script>` |

### 从不匹配的上下文发起调用

在不匹配的上下文中以静态方式调用非静态方法，[在 PHP 5.6 中已经废弃](http://php.net/manual/zh/migration56.deprecated.php#migration56.deprecated.incompatible-context)， 但是在 PHP 7.0 中， 会导致被调用方法中未定&#x4E49;*$this*变量，以及此行为已经废弃的警告。

```php
<?php
class A {
    public function test() { var_dump($this); }
}

// 注意：并没有从类 A 继承
class B {
    public function callNonStaticMethodOfA() { A::test(); }
}

(new B)->callNonStaticMethodOfA();
?>
```

Output of the above example in PHP 5.6:

```
Deprecated: Non-static method A::test() should not be called statically, assuming $this from incompatible context in /tmp/test.php on line 8
object(B)#1 (0) {
}
```

Output of the above example in PHP 7:

```
Deprecated: Non-static method A::test() should not be called statically in /tmp/test.php on line 8

Notice: Undefined variable: this in /tmp/test.php on line 3
NULL
```

### [yield](http://php.net/manual/zh/language.generators.syntax.php#control-structures.yield) 变更为右联接运算符

在使用 yield 关键字的时候，不再需要括号， 并且它变更为右联接操作符，其运算符优先级介于 print 和 => 之间。 这可能导致现有代码的行为发生改变：

```php
<?php
echo yield -1;
// 在之前版本中会被解释为：
echo (yield) - 1;
// 现在，它将被解释为：
echo yield (-1);

yield $foo or die;
// 在之前版本中会被解释为：
yield ($foo or die);
// 现在，它将被解释为：
(yield $foo) or die;
?>
```

可以通过使用括号来消除歧义。

### 函数定义不可以包含多个同名参数

在函数定义中，不可以包含两个或多个同名的参数。 例如，下面代码中的函数定义会触发`E_COMPILE_ERROR`错误：

```php
<?php
function foo($a, $b, $unused, $unused) {
    //
}
?>
```

### Switch 语句不可以包含多个 default 块

在 switch 语句中，两个或者多个 default 块的代码已经不再被支持。 例如，下面代码中的 switch 语句会触发`E_COMPILE_ERROR`错误：

```php
<?php
switch (1) {
    default:
    break;
    default:
    break;
}
?>
```

### 在函数中检视参数值会返回*当前*的值

当在函数代码中使用 [func\_get\_arg()](http://php.net/manual/zh/function.func-get-arg.php) 或 [func\_get\_args()](http://php.net/manual/zh/function.func-get-args.php) 函数来检视参数值， 或者使用 [debug\_backtrace()](http://php.net/manual/zh/function.debug-backtrace.php) 函数查看回溯跟踪， 以及在异常回溯中所报告的参数值是指参数当前的值（有可能是已经被函数内的代码改变过的值）， 而不再是参数被传入函数时候的原始值了。

```php
<?php
function foo($x) {
    $x++;
    var_dump(func_get_arg(0));
}
foo(1);?>
```

Output of the above example in PHP 5:

```
1
```

Output of the above example in PHP 7:

```
2
```

### [$HTTP\_RAW\_POST\_DATA](http://php.net/manual/zh/reserved.variables.httprawpostdata.php)被移除

不再提供 [$HTTP\_RAW\_POST\_DATA](http://php.net/manual/zh/reserved.variables.httprawpostdata.php) 变量。 请使用 [*php://input*](http://php.net/manual/zh/wrappers.php.php#wrappers.php.input) 作为替代。

### INI 文件&#x4E2D;*#*&#x6CE8;释格式被移除

在 INI 文件中，不再支持&#x4EE5;*#*&#x5F00;始的注释行， 请使&#x7528;*;*（分号）来表示注释。 此变更适用于php.ini以及用[parse\_ini\_file()](http://php.net/manual/zh/function.parse-ini-file.php)和[parse\_ini\_string()](http://php.net/manual/zh/function.parse-ini-string.php)函数来处理的文件。

### JSON 扩展已经被 JSOND 取代

JSON 扩展已经被 JSOND 扩展取代。 对于数值的处理，有以下两点需要注意的： 第一，数值不能以点号（.）结束 （例如，数值*34.*&#x5FC5;须写作*34.0*或*34*）。 第二，如果使用科学计数法表示数值，*e*前面必须不是点号（.） （例如，*3.e3*必须写作*3.0e3*或*3e3*）。 另外，空字符串不再被视作有效的 JSON 字符串。

### 在数值溢出的时候，内部函数将会失败

将浮点数转换为整数的时候，如果浮点数值太大，导致无法以整数表达的情况下， 在之前的版本中，内部函数会直接将整数截断，并不会引发错误。 在 PHP 7.0 中，如果发生这种情况，会引发 E\_WARNING 错误，并且返回`NULL`。

### 自定义会话处理器的返回值修复

在自定义会话处理器中，如果函数的返回值不是`FALSE`，也不&#x662F;*-1*， 会引发致命错误。现在，如果这些函数的返回值不是布尔值，也不&#x662F;*-1*或者*0*，函数调用结果将被视为失败，并且引发 E\_WARNING 错误。

### 相等的元素在排序时的顺序问题

由于内部排序算法进行了提升， 可能会导致对比时被视为相等的多个元素之间的顺序不稳定。

> 在对比时被视为相等的多个元素之间的排序顺序是不可信赖的，即使是相等的两个元素， 他们的位置也可能被排序算法所改变。
