PHP 7.2 参考
PHP 7.1 参考
PHP 7 于 2015 年 12 月 3 日发布。它具有许多新功能、更改和向后兼容性问题,概述如下。
表现
特征
组合比较运算符
空合并运算符
标量类型声明
返回类型声明
匿名类
Unicode 代码点转义语法
关闭call()
方法
过滤反unserialize()
IntlChar
类
期望
团体use
声明
生成器返回表达式
生成器委托
使用intdiv()
进行整数除法
session_start()
选项
preg_replace_callback_array()
函数
CSPRNG 函数
define()
中对数组常量的支持
反射添加
变化
放宽保留字限制
统一变量语法
引擎中的异常
可抛出接口
整数语义
JSON 扩展替换为 JSOND
ZPP 溢出失败
修复foreach()
的行为
list()
行为的更改
除以零语义的变化
修复自定义会话处理程序返回值
弃用 PHP 4 风格的构造函数
删除 date.timezone 警告
删除替代 PHP 标签
删除 Switch 语句中的多个默认块
删除重复名称参数的重新定义
删除死服务器 API
删除数字字符串中的十六进制支持
删除已弃用的功能
E_STRICT 通知的重新分类和删除
弃用password_hash()
的 Salt 选项
无效八进制文字错误
substr()
返回值变化
常问问题
PHP 6 发生了什么?
毫无疑问,PHP 7 最伟大的部分是它为应用程序提供了令人难以置信的性能提升。这是重构 Zend 引擎以使用更紧凑的数据结构和更少的堆分配/解除分配的结果。
实际应用程序的性能提升会有所不同,但许多应用程序似乎获得了约 100% 的性能提升 - 内存消耗也更低!
重构的代码库也为未来的优化(例如 JIT 编译)提供了进一步的机会。所以看起来未来的 PHP 版本也将继续看到性能增强。
PHP 7 性能图表比较:
使用 PHP 7 增强 Web 性能
拉斯姆斯悉尼演讲的基准
组合比较运算符(或太空船运算符)是用于从两个操作数执行三向比较的简写符号。它有一个整数返回值,可以是:
正整数(如果左侧操作数大于右侧操作数)
0(如果两个操作数相等)
负整数(如果右侧操作数大于左侧操作数)
该运算符与相等运算符( ==
、 !=
、 ===
、 !==
)具有相同的优先级,并且与其他松散比较运算符( <
、 >=
等)具有完全相同的行为。它也像它们一样是非关联的,因此不允许链接操作数(如1 <=> 2 <=> 3
)。
// 比较字符串 lexicallyvar_dump('PHP' <=> 'Node'); // int(1)// 按大小比较数字var_dump(123 <=> 456); // int(-1)// 将相应的数组元素与另一个进行比较var_dump(['a', 'b'] <=> ['a', 'b']); // 整数(0)
对象不具有可比性,因此将它们用作此运算符的操作数将导致未定义的行为。
RFC:组合比较运算符
空合并运算符(或 isset 三元运算符)是在三元运算符中执行isset()
检查的简写符号。这是应用程序中常见的事情,因此为此目的引入了新语法。
// PHP 7 之前的代码$route = isset($_GET['route']) ? $_GET['route'] : 'index';// PHP 7+ 代码$route = $_GET['route'] ?? '指数';
RFC:空合并运算符
标量类型声明有两种风格:强制(默认)和严格。现在可以强制执行以下参数类型(强制或严格):字符串 ( string
)、整数 ( int
)、浮点数 ( float
) 和布尔值 ( bool
)。它们增强了 PHP 5.x 版本中引入的其他类型:类名、接口、 array
和callable
。
// 强制模式function sumOfInts(int ...$ints) { 返回 array_sum($ints); }var_dump(sumOfInts(2, '3', 4.1)); // 整数(9)
要启用严格模式,必须将单个declare()
指令放置在文件顶部。这意味着标量输入的严格性是基于每个文件配置的。该指令不仅影响参数的类型声明,还影响函数的返回类型(请参阅返回类型声明)、内置 PHP 函数以及加载扩展中的函数。
如果类型检查失败,则会抛出TypeError
异常(请参阅引擎中的异常)。严格类型中唯一的宽松之处是当在浮点上下文中提供整数时,自动将整数转换为浮点数(反之亦然)。
声明(strict_types=1);函数乘法(float $x, float $y) { 返回 $x * $y; }函数添加(int $x,int $y) { 返回 $x + $y; }var_dump(乘法(2, 3.5)); // float(7)var_dump(add('2', 3)); // 致命错误:未捕获类型错误:传递给 add() 的参数 1 必须是整数类型,给定字符串...
请注意,执行类型检查时仅应用调用上下文。这意味着严格类型仅适用于函数/方法调用,而不适用于函数/方法定义。在上面的示例中,这两个函数可以在严格文件或强制文件中声明,但只要在严格文件中调用它们,就将应用严格的类型规则。
BC 休息
现在禁止使用名称为int
、 string
、 float
和bool
的类。
RFC:标量类型声明
返回类型声明可以指定函数、方法或闭包的返回类型。支持以下返回类型: string
、 int
、 float
、 bool
、 array
、 callable
、 self
(仅限方法)、 parent
(仅限方法)、 Closure
、类的名称和接口的名称。
函数 arraysSum(array ...$arrays): array{ return array_map(function(array $array): int { return array_sum($array); } }, $数组); }print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));/* OutputArray( [0] => 6 [1] => 15 [2] => 24)*/
对于子类型化,返回类型选择了不变性。这仅仅意味着当一个方法在子类型类中被重写或按照协定中的定义实现时,其返回类型必须与其正在(重新)实现的方法完全匹配。
A 类 {}B 类扩展 A {}C 类 { 公共函数测试():A { 返回新的 A; } }D 类扩展了 C { // 重写方法 C::test() : A public function test() : B // 由于方差不匹配而导致致命错误 { 返回新的 B; } }
重写方法D::test() : B
会导致E_COMPILE_ERROR
因为不允许协方差。为了使其工作, D::test()
方法必须具有A
的返回类型。
A 类{}接口 SomeInterface { 公共函数测试() : A; }B类实现SomeInterface { public function test() : A // 一切都好! { 返回空值; // 致命错误:未捕获类型错误:B::test() 的返回值必须是 A 的实例,返回 null... } }
这次,所实现的方法在执行时会引发TypeError
异常(请参阅引擎中的异常)。这是因为null
不是有效的返回类型 - 只能返回类A
的实例。
RFC:返回类型声明
当需要创建简单的一次性对象时,匿名类非常有用。
// PHP 7 之前的代码类记录器 { 公共函数日志($msg) { 回显 $msg; } }$util->setLogger(new Logger());// PHP 7+ 代码$util->setLogger(new class { public function log($msg) { 回显 $msg; } });
它们可以将参数传递给构造函数、扩展其他类、实现接口以及使用特征,就像普通类一样:
类 SomeClass {}接口 SomeInterface {}特征 SomeTrait {}var_dump(new class(10) 扩展 SomeClass 实现 SomeInterface { 私有 $num; 公共函数 __construct($num) { $this->num = $num; 使用 SomeTrait; });/** 输出:object(class@anonymous)#1 (1) { ["命令行代码0x104c5b612":"class@anonymous":private]=> int(10)}*/
将匿名类嵌套在另一个类中不会使其访问该外部类的任何私有或受保护的方法或属性。为了使用外部类的受保护的属性或方法,匿名类可以扩展外部类。要在匿名类中使用外部类的私有或受保护属性,必须通过其构造函数传递它们:
<?phpclass 外部 { 私人 $prop = 1; 受保护的 $prop2 = 2; 受保护函数 fun1() { 返回 3; } 公共函数 func2() { return new class($this->prop) 扩展 Outer { private $prop3; 公共函数 __construct($prop) { $this->prop3 = $prop; } 公共函数 func3() { 返回 $this->prop2 + $this->prop3 + $this->func1(); } }; } }echo (新外层)->func2()->func3(); // 6
RFC:匿名类
这使得 UTF-8 编码的 unicode 代码点能够以双引号字符串或定界符输出。接受任何有效的代码点,前导0
是可选的。
回显“u{aa}”; // ªecho "u{0000aa}"; // ª(与之前相同,但带有可选的前导 0)echo "u{9999}"; // 香
RFC:Unicode 代码点转义语法
闭包的新call()
方法用作调用闭包同时将对象范围绑定到闭包的简写方式。通过消除在调用之前创建中间闭包的需要,这可以创建更高性能和更紧凑的代码。
class A {private $x = 1;}// PHP 7 之前的代码$getXCB = function() {return $this->x;};$getX = $getXCB->bindTo(new A, 'A'); // 中间的closureecho $getX(); // 1// PHP 7+ 代码$getX = function() {return $this->x;};echo $getX->call(new A); // 1
RFC:关闭::调用
unserialize()
此功能旨在在反序列化不受信任数据上的对象时提供更好的安全性。它使开发人员能够将可反序列化的类列入白名单,从而防止可能的代码注入。
// 将所有对象转换为 __PHP_Incomplete_Class object$data = unserialize($foo, ["allowed_classes" => false]);// 将除 MyClass 和 MyClass2 之外的所有对象转换为 __PHP_Incomplete_Class 对象$data = unserialize($foo, [" allowed_classes" => ["MyClass", "MyClass2"]]);// 默认行为(与省略第二个相同)参数)接受所有类 $data = unserialize($foo, ["allowed_classes" => true]);
RFC:过滤反序列化()
IntlChar
类新的IntlChar
类旨在公开额外的 ICU 功能。该类本身定义了许多可用于操作 unicode 字符的静态方法和常量。
printf('%x', IntlChar::CODEPOINT_MAX); // 10ffffecho IntlChar::charName('@'); // 商业 ATvar_dump(IntlChar::ispunct('!')); // 布尔值(真)
为了使用此类,必须安装Intl
扩展。
BC 休息
全局命名空间中的类不得称为IntlChar
。
RFC:IntlChar 类
期望是对旧的assert()
函数的向后兼容增强。它们可以在生产代码中实现零成本断言,并提供在错误时抛出自定义异常的能力。
assert()
函数的原型如下:
void assert (mixed $expression [, mixed $message]);
与旧的 API 一样,如果$expression
是字符串,那么它将被求值。如果第一个参数为假,则断言失败。第二个参数可以是纯字符串(导致触发 AssertionError),也可以是包含错误消息的自定义异常对象。
ini_set('assert.exception', 1);class CustomError extends AssertionError {}assert(false, new CustomError('一些错误消息'));
此功能附带两个 PHP.ini 设置(及其默认值):
zend.断言= 1
断言异常 = 0
zend.assertions有三个值:
1 = 生成并执行代码(开发模式)
0 = 生成代码并在运行时跳转
-1 = 不生成任何代码(零成本,生产模式)
assert.exception表示断言失败时抛出异常。默认情况下此功能处于关闭状态,以保持与旧的assert()
函数兼容。
RFC:期望
use
声明这使得能够根据父命名空间对多个use
声明进行分组。这样做的目的是在导入同一命名空间下的多个类、函数或常量时消除代码冗长。
// PHP 7 之前的代码use somenamespaceClassA;use somenamespaceClassB;use somenamespaceClassC as C;use function somenamespacefn_a;use function somenamespacefn_b;use function somenamespace fn_c;use const somenamespaceConstA;use const somenamespaceConstB;use const somenamespaceConstC;// PHP 7+ 代码使用somenamespace{ClassA, ClassB, ClassC as C};使用函数 somenamespace{fn_a, fn_b, fn_c};使用 const somenamespace{ConstA, ConstB, ConstC};
RFC:群组使用声明
此功能建立在 PHP 5.5 中引入的生成器功能的基础上。它允许在生成器中使用return
语句来返回最终表达式(不允许通过引用返回)。可以使用新的Generator::getReturn()
方法获取该值,该方法只能在生成器完成生成值后使用。
// 现在可以使用 IIFE 语法 - 请参阅“更改”部分中的“统一变量语法”小节$gen = (function() { Yield 1; Yield 2; return 3; })();foreach ($gen as $val) { echo $val, PHP_EOL; }echo $gen->getReturn(), PHP_EOL;// 输出:// 1// 2// 3
能够从生成器显式返回最终值是一种方便的能力。这是因为它允许生成器返回最终值(可能来自某种形式的协程计算),该最终值可以由执行生成器的客户端代码专门处理。这比强制客户端代码首先检查是否已生成最终值,然后如果已生成,则专门处理该值要简单得多。
RFC:生成器返回表达式
生成器委托建立在能够从生成器返回表达式的能力之上。它通过使用新的yield from <expr>
语法来实现此目的,其中可以是任何Traversable
对象或数组。这将被推进直到不再有效,然后执行将在调用生成器中继续。此功能使yield
语句能够分解为更小的操作,从而促进具有更高可重用性的更简洁的代码。
函数 gen() { 产量 1; 产量2; 从 gen2() 返回收益率; }函数 gen2() { 产量 3; 返回4; }$gen = gen();foreach ($gen as $val) { 回显 $val, PHP_EOL; }echo $gen->getReturn();//输出// 1// 2// 3// 4
RFC:生成器委托
intdiv()
进行整数除法引入了intdiv()
函数来处理要返回整数的除法。
var_dump(intdiv(10, 3)); // 整数(3)
BC 休息
全局命名空间中的函数不得称为intdiv
。
RFC:intdiv()
session_start()
选项此功能允许将选项数组传递给session_start()
函数。这用于设置基于会话的 php.ini 选项:
session_start(['cache_limiter' => '私人']); // 将 session.cache_limiter 选项设置为私有
此功能还引入了一个新的 php.ini 设置 ( session.lazy_write
),默认情况下设置为 true,这意味着会话数据仅在发生更改时才会被重写。
RFC:引入 session_start() 选项
preg_replace_callback_array()
函数这个新函数使使用preg_replace_callback()
函数时可以更干净地编写代码。在 PHP 7 之前,需要按正则表达式执行的回调需要回调函数( preg_replace_callback()
的第二个参数)被大量分支污染(充其量是一种 hacky 方法)。
现在,可以使用关联数组将回调注册到每个正则表达式,其中键是正则表达式,值是回调。
函数签名:
string preg_replace_callback_array(array $regexesAndCallbacks, string $input);
$tokenStream = []; // [tokenName, lexeme] 对$input = <<<'end'$a = 3; // 变量初始化end;// PHP 7 之前的代码preg_replace_callback( [ '~$[a-z_][azd_]*~i', '~=~', '~[d]+~', '~;~', '~//.*~' ], function ($match) use (&$tokenStream) { if (strpos($match[0], '$') === 0) { $tokenStream[] = ['T_VARIABLE', $match[0]] ; } elseif (strpos($match[0], '=') === 0) { $tokenStream[] = ['T_ASSIGN', $match[0]]; } elseif (ctype_digit($match[0])) { $tokenStream[] = ['T_NUM', $match[0]]; } elseif (strpos($match[0], ';') === 0) { $tokenStream[] = ['T_TERMINATE_STMT', $match[0]]; } elseif (strpos($match[0], '//') === 0) { $tokenStream[] = ['T_COMMENT', $match[0]]; } }, $input);// PHP 7+ 代码preg_replace_callback_array( [ '~$[a-z_][azd_]*~i' => function ($match) use (&$tokenStream) { $tokenStream[] = ['T_VARIABLE', $match[0]]; }, '~=~' => function ($match) use (&$tokenStream) { $tokenStream[] = ['T_ASSIGN', $match[0]]; }, '~[d]+~' => function ($match) use (&$tokenStream) { $tokenStream[] = ['T_NUM', $match[0]]; }, '~;~' => 函数 ($match) use (&$tokenStream) { $tokenStream[] = ['T_TERMINATE_STMT', $match[0]]; }, '~//.*~' => function ($match) use (&$tokenStream) { $tokenStream[] = ['T_COMMENT', $match[0]]; } ], $输入);
BC 休息
全局命名空间中的函数不得称为preg_replace_callback_array
。
RFC:添加 preg_replace_callback_array 函数
此功能引入了两个新函数,用于生成加密安全整数和字符串。它们公开简单的 API 并且独立于平台。
函数签名:
string random_bytes(int length); int random_int(int min, int max);
如果找不到足够的随机性源,这两个函数都会发出Error
异常。
BC 休息
全局命名空间中的函数不得称为random_int
或random_bytes
。
RFC:简单的用户态 CSPRNG
define()
中对数组常量的支持PHP 5.6 中引入了使用const
关键字定义数组常量的功能。此功能现在也已应用于define()
函数:
定义('ALLOWED_IMAGE_EXTENSIONS', ['jpg', 'jpeg', 'gif', 'png']);
RFC:没有可用的 RFC
PHP 7 中引入了两个新的反射类。第一个是ReflectionGenerator
,用于对生成器进行内省:
反射生成器类 { 公共 __construct(Generator $gen) 公共数组 getTrace($options = DEBUG_BACKTRACE_PROVIDE_OBJECT) 公共 int getExecutingLine(void) 公共字符串 getExecutingFile(void) 公共 ReflectionFunctionAbstract getFunction(void) 公共对象 getThis(void) 公共生成器 getExecutingGenerator(void) }
第二个是ReflectionType
以更好地支持标量和返回类型声明功能:
反射类型类 { 公共 bool allowedNull(void) 公共 bool isBuiltin(void) 公共字符串 __toString(void) }
此外, ReflectionParameter
中还引入了两种新方法:
反射参数类 { // ... public bool hasType(void) public ReflectionType getType(void) }
ReflectionFunctionAbstract
中还有两个新方法:
ReflectionFunctionAbstract 类 { // ... public bool hasReturnType(void) public ReflectionType getReturnType(void) }
BC 休息
全局命名空间中的类不得称为ReflectionGenerator
或ReflectionType
。
RFC:没有可用的 RFC
现在允许在类、接口和特征中使用全局保留字作为属性、常量和方法名称。这减少了引入新关键字时 BC 中断的表面,并避免了 API 的命名限制。
这在创建具有流畅接口的内部 DSL 时特别有用:
// 'new'、'private' 和 'for' 以前不可用Project::new('项目名称')->private()->for('此处目的')->with('此处用户名');
唯一的限制是class
关键字仍然不能用作常量名,否则会与类名解析语法( ClassName::class
)冲突。
RFC:上下文敏感词法分析器
这一变化为 PHP 中的变量运算符带来了更大的正交性。它支持以前不允许的许多新的运算符组合,因此引入了新方法来以简洁的代码实现旧操作。
// 嵌套 ::$foo::$bar::$baz // 访问 $foo::$bar 属性的 $baz // 嵌套 ()foo()() // 调用 foo() 的返回// ()(function () {})() 中包含的表达式的运算符 // 来自 JS 的 IIFE 语法
任意组合变量运算符的能力来自于反转间接变量、属性和方法引用的求值语义。新的行为更加直观,并且始终遵循从左到右的评估顺序:
// 旧含义 // 新含义$$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz' ]$foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz']$foo->$bar['baz']( ) $foo->{$bar['baz']}() ($foo->$bar)['baz']() Foo::$bar['baz']() Foo::{$bar['baz']}() (Foo::$bar)['baz']()
BC 休息
依赖于旧评估顺序的代码必须重写,以明确使用带有大括号的评估顺序(请参阅上面的中间列)。这将使代码既向前兼容 PHP 7.x,又向后兼容 PHP 5.x
RFC:统一变量语法
引擎中的异常将许多致命和可恢复的致命错误转换为异常。这样可以通过自定义错误处理过程对应用程序进行正常降级。这也意味着现在将执行finally
子句和对象析构函数等清理驱动的功能。此外,通过使用应用程序错误异常,将生成堆栈跟踪以获取附加调试信息。
函数 sum(float ...$numbers) : float{ return array_sum($numbers); } 尝试 { $total = sum(3, 4, null); } catch (TypeError $typeErr) { // 在此处理类型错误}
新的异常层次结构如下:
interface Throwable |- Exception implements Throwable |- ... |- Error implements Throwable |- TypeError extends Error |- ParseError extends Error |- AssertionError extends Error |- ArithmeticError extends Error |- DivisionByZeroError extends ArithmeticError
有关此新异常层次结构的更多信息,请参阅“更改”部分中的“可抛出接口”小节。
BC 休息
用于处理(通常忽略)可恢复致命错误的自定义错误处理程序将不再起作用,因为现在将抛出异常
eval()
代码中发生的解析错误现在将成为异常,需要将它们包装在try...catch
块中
RFC:引擎中的异常
由于在引擎中引入了异常,此更改会影响 PHP 的异常层次结构。我们决定实现一个新的Exception
层次结构,以防止 PHP 5.x 代码使用 catch-all ( catch (Exception $e)
) 条款。
新的异常层次结构如下:
interface Throwable |- Exception implements Throwable |- ... |- Error implements Throwable |- TypeError extends Error |- ParseError extends Error |- AssertionError extends Error |- ArithmeticError extends Error |- DivisionByZeroError extends ArithmeticError
Throwable
接口由Exception
和Error
基类层次结构实现,并定义以下约定:
interface Throwable { final public string getMessage ( void ) final public mixed getCode ( void ) final public string getFile ( void ) final public int getLine ( void ) final public array getTrace ( void ) final public string getTraceAsString ( void ) public string __toString ( void ) }
Throwable
不能由用户定义的类实现 - 相反,自定义异常类应该扩展 PHP 中预先存在的异常类之一。
RFC:可抛出接口
某些基于整数的行为的语义已发生变化,以使它们更加直观且独立于平台。以下是这些更改的列表:
将NAN
和INF
转换为整数将始终得到 0
现在不允许按负数位进行按位移位(导致 bool(false) 返回并发出 E_WARNING)
按位左移超出整数位宽的位数将始终导致 0
按位右移超出整数位宽的位数将始终导致 0 或 -1(取决于符号)
BC 休息
对上述旧语义的任何依赖将不再有效
RFC:整数语义
旧的 JSON 扩展的许可被认为是非免费的,这给许多基于 Linux 的发行版带来了问题。该扩展已被 JSOND 取代,并带来了一些性能提升和向后兼容性破坏。
BC 休息
数字不得以小数点结尾(即34.
必须更改为34.0
或仅更改为34
)
e
指数不得紧跟小数点(即3.e3
必须更改为3.0e3
或仅更改为3e3
)
RFC:用 jsond 替换当前的 json 扩展
当将浮点数传递给需要整数的内部函数时,可能会发生浮点数到整数之间的强制转换。如果浮点数太大而无法表示为整数,则该值将被静默截断(这可能会导致幅度和符号丢失)。这可能会引入难以发现的错误。因此,此更改旨在在发生从浮点到整数的隐式转换并失败时通过返回null
并发出 E_WARNING 来通知开发人员。
BC 休息
曾经默默工作的代码现在将发出 E_WARNING,并且如果函数调用的结果直接传递给另一个函数(因为现在将传入null
),则可能会失败。
RFC:ZPP 溢出失败
foreach()
的行为PHP 的foreach()
循环有许多奇怪的边缘情况。这些都是实现驱动的,并且在数组的副本和引用之间进行迭代时、使用current()
和reset()
等迭代器操纵器时、修改当前正在迭代的数组时等时,会导致许多未定义和不一致的行为。
这一变化消除了这些边缘情况的未定义行为,并使语义更加可预测和直观。
foreach()
按数组值
$array = [1,2,3];$array2 = &$array;foreach($array as $val) { 取消设置($array[1]); // 修改正在迭代的数组 echo "{$val} - ", current($array), PHP_EOL; }// PHP 7 之前的结果1 - 33 -// PHP 7+ 结果1 - 12 - 13 - 1
当使用按值语义时,正在迭代的数组现在不会就地修改。 current()
现在也定义了行为,它始终从数组的开头开始。
foreach()
通过数组和对象的引用以及对象的值
$array = [1,2,3];foreach($array as &$val) { echo "{$val} - ", current($array), PHP_EOL; }// PHP 7 之前的结果1 - 22 - 33 -// PHP 7+ 结果1 - 12 - 13 - 1
current()
函数不再受foreach()
在数组上的迭代的影响。此外,嵌套的foreach()
使用引用语义现在彼此独立工作:
$array = [1,2,3];foreach($array as &$val) { echo $val, PHP_EOL; foreach ($array as &$val2) { 取消设置($array[1]); 回显$val,PHP_EOL; } }// PHP 7 之前的结果111// PHP 7+ 结果111333
BC 休息
对旧的(古怪的和未记录的)语义的任何依赖都将不再有效。
RFC:修复“foreach”行为
list()
行为的更改list()
函数被记录为不支持字符串,但在少数情况下可以使用字符串:
// 数组解引用$str[0] = 'ab';list($a, $b) = $str[0];echo $a; // 回声 $b; // b// 对象解引用$obj = new StdClass();$obj->prop = 'ab';list($a, $b) = $obj->prop;echo $a; // 回声 $b; // b// 函数返回函数 func() { 返回 'ab'; }list($a, $b) = func();var_dump($a, $b);echo $a; // 回声 $b; // 乙
现在这一点已更改,在所有情况下都禁止使用list()
进行字符串使用。
此外,空list()
现在是一个致命错误,并且分配变量的顺序已更改为从左到右:
$a = [1, 2];list($a, $b) = $a;// 旧的: $a = 1, $b = 2// 新的: $a = 1, $b = null + "未定义索引 1"$b = [1, 2];list($a, $b) = $b;// 旧: $a = null + "未定义索引 0", $b = 2// 新: $a = 1、$b = 2
BC 休息
使list()
等于任何非直接字符串值不再可能。 null
现在将是上面示例中变量$a
和$b
的值
调用不带任何变量的list()
将导致致命错误
依赖旧的从右到左的分配顺序将不再起作用
RFC:修复 list() 行为不一致
RFC:抽象语法树
在 PHP 7 之前,当除法 (/) 或模数 (%) 运算符的除数为 0 时,将发出 E_WARNING 并返回false
。在某些情况下,算术运算返回布尔值是荒谬的,因此该行为已在 PHP 7 中得到纠正。
新行为导致除法运算符返回 +INF、-INF 或 NAN 形式的浮点数。模数运算符 E_WARNING 已被删除,并且(与新的intdiv()
函数一起)将引发DivisionByZeroError
异常。此外,当提供有效的整数参数时, intdiv()
函数也可能引发ArithmeticError
,从而导致不正确的结果(由于整数溢出)。
var_dump(3/0); // 浮动(INF) + E_WARNINGvar_dump(0/0); // 浮动(NAN) + E_WARNINGvar_dump(0%0); // DivisionByZeroErrorintdiv(PHP_INT_MIN, -1); // 算术错误
BC 休息
除法运算符将不再返回false
(这可能在算术运算中默默地强制为 0)
模运算符现在将抛出除数为 0 的异常,而不是返回false
RFC:没有可用的 RFC
实现自定义会话处理程序时, SessionHandlerInterface
中期望返回true
或false
值的谓词函数未按预期运行。由于之前实现中的错误,只有-1
返回值被认为是 false - 这意味着即使使用布尔值false
来表示失败,也会被视为成功:
<?phpclass FileSessionHandler 实现 SessionHandlerInterface { 私人 $savePath; 函数打开($savePath,$sessionName) { 返回假; // 总是失败 } 函数 close(){return true;} 函数 read($id){} 函数 write($id, $data){} 函数 destroy($id){} 函数 gc($maxlifetime){} }session_set_save_handler(new FileSessionHandler());session_start(); // 在 PHP 7 之前的代码中不会导致错误
现在,上述操作将失败并出现致命错误。返回值-1
也将继续失败,而0
和true
将继续意味着成功。返回的任何其他值现在都将导致失败并发出 E_WARNING。
BC 休息
如果返回boolean false
,现在实际上会失败
如果返回布尔值、 0
或-1
以外的任何值,它将失败并导致发出警告
RFC:修复自定义会话处理程序返回值的处理
PHP 4 构造函数与新的__construct()
一起保留在 PHP 5 中。现在,PHP 4 风格的构造函数已被弃用,取而代之的是在对象创建时仅调用一个方法 ( __construct()
)。这是因为是否调用 PHP 4 样式构造函数的条件会给开发人员带来额外的认知开销,这也可能会让没有经验的人感到困惑。
例如,如果该类是在命名空间中定义的,或者如果存在__construct()
方法,则 PHP 4 样式的构造函数将被识别为普通方法。如果它是在__construct()
方法之上定义的,则将发出 E_STRICT 通知,但仍被识别为普通方法。
现在在 PHP 7 中,如果该类不在命名空间中并且不存在__construct()
方法,则 PHP 4 样式构造函数将用作构造函数,但将发出 E_DEPRECATED。在 PHP 8 中,PHP 4 风格的构造函数将始终被识别为普通方法,并且 E_DEPRECATED 通知将消失。
BC 休息
自定义错误处理程序可能会受到 E_DEPRECATED 警告的影响。要解决此问题,只需将类构造函数名称更新为__construct
即可。
RFC:删除 PHP 4 构造函数
当调用任何基于日期或时间的函数并且尚未设置默认时区时,会发出警告。解决方法是简单地将date.timezone
INI 设置设置为有效的时区,但这迫使用户拥有 php.ini 文件并预先配置它。由于这是唯一附加了警告的设置,并且无论如何它都默认为 UTC,因此该警告现已被删除。
RFC:删除 date.timezone 警告
替代 PHP 标签<%
(和<%=
)、 %>
、 <script language="php">
和</script>
现已删除。
BC 休息
依赖这些替代标签的代码需要更新为正常或短的开始和结束标签。这可以手动完成,也可以使用此移植脚本自动完成。
RFC:删除替代 PHP 标签
以前,可以在 switch 语句中指定多个default
块语句(仅执行最后一个default
块)。这种(无用的)能力现已被删除,并会导致致命错误。
BC 休息
任何使用多个default
块创建 switch 语句的编写(或更可能生成)代码现在都将成为致命错误。
RFC:使在开关中定义多个默认情况成为语法错误
以前,可以在函数定义中指定具有重复名称的参数。此功能现已被删除并会导致致命错误。
函数 foo($version, $version) { 返回 $版本; }echo foo(5, 7);// PHP 7 之前的结果7// PHP 7+ 结果致命错误:在 /redefinition-of-parameters.php 中重新定义参数 $version
BC 休息
具有重复名称的函数参数现在将成为致命错误。
以下 SAPI 已从核心中删除(其中大部分已移至 PECL):
sapi/aolserver
sapi/阿帕奇
sapi/apache_hooks
sapi/apache2filter
萨皮/卡迪姆
sapi/连续性
萨皮/伊萨皮
萨皮/米尔特
sapi/nsapi
sapi/phttpd
sapi/pi3web
萨皮/罗克森
sapi/thttpd
萨皮/晚礼服
sapi/webjames
分机/mssql
分机/mysql
ext/sybase_ct
分机/ereg
RFC:删除死的或尚未 PHP7 移植的 SAPI 和扩展
Stringy 十六进制数不再被识别为数字。
var_dump(is_numeric('0x123'));var_dump('0x123' == '291');echo '0x123' + '0x123';// PHP 7 之前的结果bool(true)bool(true)582// PHP 7+结果布尔(假)布尔(假)0
进行此更改的原因是为了提高跨语言处理字符串十六进制数字之间的一致性。例如,显式转换无法识别字符串十六进制数字:
var_dump((int) '0x123'); // 整数(0)
相反,应该使用filter_var()
函数验证和转换字符串十六进制数字:
var_dump(filter_var('0x123', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX)); // 整数(291)
BC 休息
此更改会影响is_numeric()
函数和各种运算符,包括==
、 +
、 -
、 *
、 /
、 %
、 **
、 ++
和--
RFC:删除数字字符串中的十六进制支持
所有已弃用的功能已被删除,最值得注意的是:
原来的mysql扩展(ext/mysql)
ereg 扩展名 (ext/ereg)
通过引用分配new
来自不兼容的$this
上下文的非静态方法的作用域调用(例如来自类外部的Foo::bar()
,其中bar()
不是静态方法)
BC 休息
任何在 PHP 5 中运行时带有弃用警告的代码都将不再工作(您已收到警告!)
RFC:删除 PHP 7 中已弃用的功能
E_STRICT 通知的含义一直处于灰色地带。此更改完全删除了此错误类别,并且:删除 E_STRICT 通知,如果将来将删除该功能,则将其更改为 E_DEPRECATED,将其更改为 E_NOTICE,或将其提升为 E_WARNING。
BC 休息
由于 E_STRICT 属于最低严重性错误类别,因此任何升级为 E_WARNING 的错误都可能会破坏自定义错误处理程序
RFC:重新分类 E_STRICT 通知
password_hash()
的 Salt 选项随着 PHP 5.5 中新密码哈希 API 的引入,许多人开始实现它并生成自己的盐。不幸的是,许多这些盐是由像 mt_rand() 这样的加密不安全函数生成的,使得盐比默认生成的盐要弱得多。 (是的,使用这个新 API 对密码进行哈希处理时始终使用盐!)因此,生成盐的选项已被弃用,以防止开发人员创建不安全的盐。
RFC:没有可用的 RFC
无效的八进制文字现在将导致解析错误,而不是被截断并默默地忽略。
回声0678; // 解析错误:无效的数字文字...
BC 休息
代码中任何无效的八进制文字现在都会导致解析错误
RFC:没有可用的 RFC
substr()
返回值变化当截断的起始位置等于字符串长度时, substr()
现在将返回一个空字符串而不是false
:
var_dump(substr('a', 1));// PHP 7 之前 resultbool(false)// PHP 7+ resultstring(0) ""
然而,在其他情况下, substr()
仍可能返回false
。
BC 休息
严格检查bool(false)
返回值的代码现在可能在语义上无效
RFC:没有可用的 RFC
PHP 6 是从未曝光的主要 PHP 版本。它的核心应该是全面支持 Unicode,但这一努力过于雄心勃勃,带来了太多的复杂性。此新主要版本跳过版本 6 的主要原因如下:
以防混乱。许多资源都是关于 PHP 6 的,并且社区中的许多人都知道其中的功能。 PHP 7 是一个完全不同的野兽,具有完全不同的关注点(特别是性能)和完全不同的功能集。因此,我们跳过了一个版本,以防止对 PHP 7 产生任何混淆或误解。
让熟睡的狗躺着。 PHP 6 被视为失败,大量 PHP 6 代码仍然保留在 PHP 存储库中。因此,最好的办法是跳过版本 6,并在下一个主要版本(版本 6)上重新开始。
RFC:PHP 下一版本的名称