PHP 8.1更新

PHP8.1 体验

枚举

使用
//值为整形
enum IntEnum:int{
    case AAA=1;
    case BBB=2;
    case CCC=3;
}
//值为 string 型
enum StringEnum:string{
    case AAA='one';
    case BBB='two';
    case CCC='three';
}
class About{
    public function __construct(public IntEnum $status)
    {}
}
$about=new About(IntEnum::AAA);
dd($about->status);//输出 name 为 AAA 的选项
dd($about->status->name);//输出结果 "AAA"
dd($about->status->cases());;//输出所有选项
dd(IntEnum::from(1));//输出 value 为 1的选项
dd(IntEnum::tryFrom(5));//不存在时输出 null
方法

Enum 可以作为作为传参类型绑定,或者设定返回值的类型。

enum IntEnum:int{
    case AAA=1;
    case BBB=2;
    case CCC=3;
}
//可以作为传参类型绑定和返回值
function label_enum_function(IntEnum $value){
    return match ($value){
      IntEnum::AAA => '一切正常',
      IntEnum::BBB => '无权访问',
      IntEnum::CCC => '页面未找到'  
    };
}
class HTTPReturn{
    public function __construct(public IntEnum $status)
    {
    }
}
$reponse = new HTTPReturn(IntEnum::BBB);
dd(label_enum_function($reponse->status));//'无权访问'

函数 label_enum_function () 可以通过在 Enum 里写方法的方式来解决:

enum IntEnum: int {
    case AAA = 1;
    case BBB = 2;
    case CCC = 3;

    public function label(): string {
        return static::getLabel($this);
    }

    public static function getLabel(self $value): string {
        return match ($value) {
            IntEnum::AAA => '一切正常',
            IntEnum::BBB => '无权访问',
            IntEnum::CCC => '页面未找到',
        };
    }
}

class HTTPReturn
{
    public function __construct(
        public IntEnum $status, 
    ) {} 
}

// "一切正常"
dump(IntEnum::AAA->label());
dump(IntEnum::getLabel(IntEnum::AAA));
$response = new HTTPReturn(IntEnum::AAA);
dump($response->status->label());
exit;
使用 Trait 的 Enum

Trait 里不能包含属性,只能包含方法

trait HTTPReturn{
    public function label(): string {
        return static::getLabel($this);
    }

    public static function getLabel(self $value): string {
        return match ($value) {
            IntEnum::AAA => '一切正常',
            IntEnum::BBB => '无权访问',
            IntEnum::CCC => '页面未找到',
        };
    }
}
enum IntEnum: int {
    use HTTPReturn;
    case AAA = 1;
    case BBB = 2;
    case CCC = 3;
}
//"一切正常"
dd(IntEnum::AAA->label());
dd(IntEnum::getLabel(IntEnum::AAA));
继承 interface 的 Enum
interface APIEnum
{
  public function label():string;
}
//继承后 必须实现 label 方法
enum IntEnum:int implements APIEnum{
  case AAA = 1;
  case BBB = 2;
  case CCC = 3;
  public function label():string{
    return match($this){
        IntEnum::AAA => '一切正常',
        IntEnum::BBB => '无权访问',
        IntEnum::CCC => '页面未找到',
    };
  }
}
class HTTPReturn
{
  public function __construct(
        public IntEnum $status, 
  ) {} 
}
$reponse = new HTTPReturn(IntEnum::AAA);
dd($reponse->status);
Enum 和类的区别
  • 不能使用 extends
  • Enum 不能有状态( 不能使用类属性 )
  • 可以使用类常量
enum IntEnum {
    case AAA;
    case BBB;

    public const DEFAULT = self::AAA;
}

class User
{
    public function __construct(
        public IntEnum $status, 
    ) {} 
}

$user = new User(IntEnum::AAA);
dd($user->status);//"AAA"

数组

解包数组

一维数组

$array_1 = ['a','b'];
$array_2 = ['c','d'];
$array_unpacked = [...$array_1,...$array_2,...['e']];
$array_merged = array_merge($array_1,$array_2,['e']);

// ['a', 'b', 'c', 'd', 'e'];
dump($array_unpacked);
dump($array_merged);

支持二维数组

$array_1 = [
  'k1' => 'v1',
  'k2' => 'v2'
];
$array_2 = [
  'k3' => 'v3',
  'k4' => 'v4'
];
$array_unpacked = [...$array_1, ...$array_2];
$array_merged   = array_merge($array_1, $array_2);
//[ "k1" => "v1","k2" => "v2","k3" => "v3","k4" => "v4"]
dump($array_unpacked);
//true
dd($array_merged == $array_unpacked);

解包数组和 + 操作符

dump(
    ['k' => 'v1']
   +['k' => 'v2']
);

dump([
    ...['k' => 'v1'],
    ...['k' => 'v2']
]);
// + 运算符
array:1 ["k" => "v1"
]
// 解包数组
array:1 ["k" => "v2"
]

加号运算符会跳过相同 Key 的值,而解包数组会覆盖相同 Key 的值

array_is_list() 方法

判断是否是从 0 开始递增的数字数组(0 开始: true 其他: false)

//true 
dump(array_is_list([1, 2, 3]));
dump(array_is_list(['apple', 'orange']));
dump(array_is_list(['apple', 2, 3]));
dump(array_is_list([0 => 'apple', 'orange']));
dump(array_is_list([0 => 'apple', 1 => 'orange']));
dump(array_is_list([]));
//false
dump(array_is_list([1 => 'apple', 'orange']));
dump(array_is_list([1 => 'apple', 0 => 'orange']));
dump(array_is_list([0 => 'apple', 'foo' => 'bar']));
dump(array_is_list([0 => 'apple', 2 => 'bar']));

函数

可调用语法 First-class Callable

1. 对比 Closure::fromCallable

对比php 7.1 发布的 Closure::fromCallable

$callable = Closure::fromCallable('strtoupper');
echo $callable('hello, world') . PHP_EOL; 

php 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();
//1638270664
echo $get_time() . PHP_EOL;

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);
never 返回类型

1. 规则
  设置了 never 作为返回类型的函数或者方法,必须是这三种情况之一:
   - die();
   - exit();
   - 或者抛出异常

function redirect(string $url): never {
    header('Location: ' . $url);
    exit();
}

never 返回类型的目的是为了保证代码运行以后,其他后面的代码将不会运行。

2. 正确的例子

function redirect(string $url): never {
    header('Location: ' . $url);
    exit();
}

redirect('Test'); 

echo "这行代码永远不会被执行";

3. 没有终止程序
  如果声明了 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 

4. 不允许 return void

//return void 的函数:
function doSomeThing(): never {
    return;
}
doSomeThing();

报错

Fatal error: A never-returning function must not return in

5. 类继承
  类继承里面,如果父类的方法是返回值是 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值