005. PHP 8.1 更新函数相关:可调用语法和 never return 类型

本视频源码 github.com/LearnKu-LX4/001_005_php...

说明

大家好,这个视频我来演示 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

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
Summer
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
发起讨论 只看当前版本


暂无话题~