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