005. PHP 8.1 更新函数相关:可调用语法和 never return 类型
说明
大家好,这个视频我来演示 PHP 8.1 的可调用语法和 never 返回类型。
可调用语法 First-class Callable
1. 对比 Closure::fromCallable
我们先来看下之前 PHP 7.1 发布的 Closure::fromCallable
可调用变量功能:
$callable = Closure::fromCallable('strtoupper');
echo $callable('hello, world') . PHP_EOL;
在新的 8.1 语法里,使用以下对等于上面:
$callable = strtoupper(...);
echo $callable('hello, world') . PHP_EOL;
2. 语法
可调用的方法或者函数名称,后面加 (...)
。
四种常见 Callable 如下;
<?php
// 1. 函数
$callable = strlen(...);
echo $callable('hello world') . PHP_EOL;
// 2. 类方法
class User {
public function __construct(
public string $first_name,
public string $last_name
){}
public function getFullName()
{
return $this->first_name .' '. $this->last_name;
}
}
$user = new User('Charlie', 'Jade');
$fullname = $user->getFullName(...);
echo $fullname() . PHP_EOL;
// 3. Static 方法
class Str{
public static function toLower(string $string)
{
return strtolower($string);
}
}
$callable = Str::toLower(...);
echo $callable('HELLO WORLD~') . PHP_EOL;
// 4. 匿名函数
$function = function($string) {
return str_shuffle($string);
};
$callable = $function(...);
echo $callable('Hello World!') . PHP_EOL;
会打印:
11
Charlie Jade
hello world~
rloWod! eHll
3. 调用 Scope
下面这个例子:
function shout(): void {
$value = 'Banana';
echo $value;
}
$value = 'Apple';
$callable = shout(...);
echo $callable();
会返回,变量范围会被继承:
Banana
下面这个例子演示了可以将 private 方法作为 callable
对象返回:
<?php
class Clock {
public function getClockCallable(): callable {
return $this->getTime(...);
}
private function getTime(): int {
return time();
}
}
$clock = new Clock();
$get_time = $clock->getClockCallable();
echo $get_time() . PHP_EOL;
会输出:
1638270664
4. 将 Callable 作为参数
PHP 8.1 之前:
function double($value)
{
return 2 * $value;
}
$array = [1, 2, 3, 4, 5];
$doubled = array_map('double', $array);
print_r($doubled);
PHP 8.1以后:
function double($value)
{
return 2 * $value;
}
$array = [1, 2, 3, 4, 5];
$doubled = array_map(double(...), $array);
print_r($doubled);
在这个例子中,使用可调用语法的好处是 double 在 IDE 下是可点击的,另外也方便一些静态分析工具,在你还没有运行代码之前就告诉你会发生错误。
never 返回类型
1. 规则
设置了 never 作为返回类型的函数或者方法,必须在是三种情况之一:
- die();
- exit();
- 或者抛出异常。
语法如下:
function redirect(string $url): never {
header('Location: ' . $url);
exit();
}
never 返回类型的目的是为了保证代码运行以后,其他后面的代码将不会运行。
1. 正确的例子
例如像下面这个例子:
function redirect(string $url): never {
header('Location: ' . $url);
exit();
}
redirect('Test');
echo "这行代码永远不会被执行";
2. 没有终止程序
如果声明了 never 返回类型,但是没有 exit / die 或抛出异常:
function redirect(string $url): never {
header('Location: ' . $url);
}
redirect('Test');
会报错:
Fatal error: Uncaught TypeError: redirect(): never-returning function must not implicitly return
3. 不允许 return void
return void 的函数:
function doSomeThing(): never {
return;
}
doSomeThing();
也会报错:
Fatal error: A never-returning function must not return in
4. 类继承
类继承里面,如果父类的方法是返回值是 string 或者其他高级的返回类型,子类继承的时候是可以变更为 never 类型的:
class Foo {
public function test(): string {}
}
class FooBar extends Foo{
public function test(): never {}
}
是可以运行通过的。
如果父类方法里设置了 never 作为返回类,则子类方法里不能使用其他返回类型::
class Foo {
public function test(): never {}
}
class FooBar extends Foo{
public function test(): string {}
}
会报错:
Fatal error: Declaration of FooBar::test(): string must be compatible with Foo::test(): never