记住飞船运算符表达式返回什么的一个好经验法则是用减号 (-) 替换飞船运算符。如果结果为负数、0 或正数,则表达式将分别返回 -1、0 或 1。
示例
<?php
echo 5 <=> 8; // 5 - 8 = -3, 打印 -1
echo 2 <=> 2; // 2 - 2 = 0, 打印 0
echo 4 <=> 2; // 4 - 2 = 2, 打印 1
标量 类型声明 有两种形式:强制(默认)和严格。现在可以强制执行以下参数类型(强制或严格):字符串 (string)、整数 (int
)、浮点数 (float) 和布尔值 (bool
)。它们增强了 PHP 5 中引入的其他类型:类名、接口、array 和 callable。
<?php
// 强制模式
function sumOfInts(int ...$ints)
{
return array_sum($ints);
}
var_dump(sumOfInts(2, '3', 4.1));
上面的例子将输出
int(9)
要启用严格模式,必须在文件开头放置一个 declare
指令。这意味着标量类型的严格性是在每个文件的基础上配置的。此指令不仅影响参数的类型声明,还影响函数的返回类型(参见 返回类型声明、内置 PHP 函数和加载扩展中的函数。
可以在 类型声明 参考中找到标量类型声明的完整文档和示例。
PHP 7 添加了对 返回类型声明 的支持。与 参数类型声明 类似,返回类型声明指定从函数返回的值的类型。返回类型声明可以使用与参数类型声明相同的 类型。
<?php
function arraysSum(array ...$arrays): array
{
return array_map(function(array $array): int {
return array_sum($array);
}, $arrays);
}
print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));
上面的例子将输出
Array ( [0] => 6 [1] => 15 [2] => 24 )
可以在 返回类型声明 中找到返回类型声明的完整文档和示例。
空值合并运算符 (??
) 作为语法糖添加到需要将三元运算符与 isset() 结合使用的情况中。如果它的第一个操作数存在并且不是 null
,则返回它的第一个操作数;否则返回它的第二个操作数。
<?php
// 获取 $_GET['user'] 的值,如果不存在则返回 'nobody'
$username = $_GET['user'] ?? 'nobody';
// 这等同于:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
// 可以将合并操作链接在一起:这将返回 $_GET['user']、$_POST['user'] 和 'nobody' 中的第一个定义值。
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>
太空船运算符用于比较两个表达式。当 $a 分别小于、等于或大于 $b 时,它返回 -1、0 或 1。比较是根据 PHP 通常的 类型比较规则 执行的。
<?php
// 整数
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1
// 浮点数
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1
// 字符串
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
?>
现在可以使用 define() 定义 Array 常量。在 PHP 5.6 中,它们只能使用 const
定义。
<?php
define('ANIMALS', [
'dog',
'cat',
'bird'
]);
echo ANIMALS[1]; // 输出 "cat"
?>
通过 new class
添加了对匿名类的支持。这些类可以用作一次性对象,以代替完整类定义。
<?php
interface Logger {
public function log(string $msg);
}
class Application {
private $logger;
public function getLogger(): Logger {
return $this->logger;
}
public function setLogger(Logger $logger) {
$this->logger = $logger;
}
}
$app = new Application;
$app->setLogger(new class implements Logger {
public function log(string $msg) {
echo $msg;
}
});
var_dump($app->getLogger());
?>
上面的例子将输出
object(class@anonymous)#2 (0) { }
完整的文档可以在 匿名类参考 中找到。
此语法使用十六进制形式的 Unicode 代码点,并将该代码点输出为 UTF-8 编码的双引号字符串或 heredoc。任何有效的代码点都可以接受,前导 0 可以省略。
<?php
echo "\u{aa}", PHP_EOL;
echo "\u{0000aa}", PHP_EOL;
echo "\u{9999}", PHP_EOL;
echo <<<EOT
\u{01f418}
EOT;
?>
上面的例子将输出
ª ª (same as before but with optional leading 0's) 香
Closure::call() 是一种更高效的简写方式,可以临时将对象作用域绑定到闭包并调用它。
<?php
class A {private $x = 1;}
// PHP 7 之前的代码
$getX = function() {return $this->x;};
$getXCB = $getX->bindTo(new A, 'A'); // 中间闭包
echo $getXCB();
// PHP 7+ 代码
$getX = function() {return $this->x;};
echo $getX->call(new A);
上面的例子将输出
1 1
此功能旨在为在不可信数据上反序列化对象提供更好的安全性。它通过允许开发人员将可以反序列化的类列入白名单来防止可能的代码注入。
<?php
// 将所有对象转换为 __PHP_Incomplete_Class 对象
$data = unserialize($foo, ["allowed_classes" => false]);
// 将所有对象转换为 __PHP_Incomplete_Class 对象,除了 MyClass 和 MyClass2 的对象
$data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]]);
// 默认行为(与省略第二个参数相同),接受所有类
$data = unserialize($foo, ["allowed_classes" => true]);
新的 IntlChar 类旨在公开更多 ICU 功能。该类本身定义了许多静态方法和常量,可用于操作 Unicode 字符。
<?php
printf('%x', IntlChar::CODEPOINT_MAX);
echo IntlChar::charName('@');
var_dump(IntlChar::ispunct('!'));
上面的例子将输出
10ffff COMMERCIAL AT bool(true)
要使用此类,必须安装 Intl 扩展。
断言是对旧的 assert() 函数向后兼容的增强功能。它们允许在生产代码中进行零成本断言,并提供在断言失败时抛出自定义异常的能力。
虽然旧的 API 为了兼容性而继续维护,但 assert() 现在是一个语言结构,允许第一个参数是一个表达式,而不仅仅是一个 string 用于评估或一个 bool 值用于测试。
<?php
ini_set('assert.exception', 1);
class CustomError extends AssertionError {}
assert(false, new CustomError('Some error message'));
?>
上面的例子将输出
Fatal error: Uncaught CustomError: Some error message
有关此功能的完整详细信息,包括如何在开发和生产环境中配置它,可以在 assert() 语言结构的手册页上找到。
use
声明从同一个 namespace
导入的类、函数和常量现在可以分组到一个 use
语句中。
<?php
// PHP 7 之前的代码
use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;
use function some\namespace\fn_a;
use function some\namespace\fn_b;
use function some\namespace\fn_c;
use const some\namespace\ConstA;
use const some\namespace\ConstB;
use const some\namespace\ConstC;
// PHP 7+ 代码
use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};
?>
此功能建立在 PHP 5.5 中引入的生成器功能之上。它允许在生成器中使用 return
语句,以便能够返回最终表达式(不允许按引用返回)。可以使用新的 Generator::getReturn()
方法获取此值,该方法只能在生成器完成生成值后使用。
<?php
$gen = (function() {
yield 1;
yield 2;
return 3;
})();
foreach ($gen as $val) {
echo $val, PHP_EOL;
}
echo $gen->getReturn(), PHP_EOL;
上面的例子将输出
1 2 3
能够从生成器中显式返回最终值是一个方便的功能。这是因为,它允许生成器返回最终值(例如,来自某种协程计算),该值可以由执行生成器的客户端代码专门处理。这比强制客户端代码首先检查是否已生成最终值,然后如果已生成,则专门处理该值要简单得多。
生成器现在可以使用 yield from
结构自动委托给另一个生成器、Traversable 对象或 array,而无需在最外层生成器中编写样板代码。
<?php
function gen()
{
yield 1;
yield 2;
yield from gen2();
}
function gen2()
{
yield 3;
yield 4;
}
foreach (gen() as $val)
{
echo $val, PHP_EOL;
}
?>
上面的例子将输出
1 2 3 4
session_start() 现在接受一个 数组 选项,这些选项会覆盖通常在 php.ini 中设置的 会话配置指令。
这些选项也已扩展为支持 session.lazy_write,该选项默认开启,它会导致 PHP 仅在会话数据发生变化时才覆盖任何会话文件,以及 read_and_close
,该选项只能传递给 session_start() 以指示应该读取会话数据,然后会话应立即以不变状态关闭。
例如,要将 session.cache_limiter 设置为 private
,并在读取会话后立即关闭它
<?php
session_start([
'cache_limiter' => 'private',
'read_and_close' => true,
]);
?>
新的 preg_replace_callback_array() 函数允许在使用 preg_replace_callback() 函数时编写更简洁的代码。在 PHP 7 之前,需要针对每个正则表达式执行的回调需要回调函数包含大量分支。
现在,可以使用关联数组将回调注册到每个正则表达式,其中键是正则表达式,值是回调。
添加了两个新函数以跨平台方式生成加密安全的整数和字符串:random_bytes() 和 random_int().
以前,list() 不能保证对实现 ArrayAccess 的对象执行正确操作。此问题已修复。
(clone $foo)->bar()
。
记住飞船运算符表达式返回什么的一个好经验法则是用减号 (-) 替换飞船运算符。如果结果为负数、0 或正数,则表达式将分别返回 -1、0 或 1。
示例
<?php
echo 5 <=> 8; // 5 - 8 = -3, 打印 -1
echo 2 <=> 2; // 2 - 2 = 0, 打印 0
echo 4 <=> 2; // 4 - 2 = 2, 打印 1
在 php 7.0 中,可以以类似于 JavaScript 的方式对函数进行柯里化。
<?php
// 一个柯里化的函数
function add($a) {
return function($b) use ($a) {
return $a + $b;
};
}
// 在 PHP 7 中调用柯里化函数
$result = add(10)(15);
var_dump($result); // int 25
?>
在 php 5.6 中无法进行这种柯里化。