# 数组
# 解构赋值 7.1
您可以 解构数组,将多个元素提取到单独的变量中:$array = [1, 2, 3];
// 使用list语法:
list($a, $b, $c) = $array;
// 或速记语法:
[$a, $b, $c] = $array;
您可以跳过元素:
[, , $c] = $array;
// $c = 3
以及基于键的解构:
$array = [
'a' => 1,
'b' => 2,
'c' => 3,
];
['c' => $c, 'a' => $a] = $array;
# 剩余和展开操作符 5.6
数组可以展开到函数中:$array = [1, 2];
function foo(int $a, int $b) { /* … */ }
foo(...$array);
函数可以使用同一运算符自动收集其余变量:
function foo($first, ...$other) { /* … */ }
foo('a', 'b', 'c', 'd', …);
剩余参数甚至可以类型提示:
function foo($first, string ...$other) { /* … */ }
foo('a', 'b', 'c', 'd', …);
7.4
具有数值键的数组也可以展开到新数组中:
$a = [1, 2];
$b = [3, 4];
$result = [...$a, ...$b]; // [1, 2, 3, 4]
8.1
您还可以从 PHP 8.1 开始使用字符串键展开数组
# Attributes注解 8.0
通过使用#[Attribute]
标记类来创建自己的类
#[Attribute]
class ListensTo
{
public string $event;
public function __construct(string $event)
{
$this->event = $event;
}
}
你可以将它们添加到属性、(匿名)类、函数、常量、闭包、函数参数中:
#[
Route(Http::POST, '/products/create'),
Autowire,
]
class ProductsCreateController
{
public function __invoke() { /* … */ }
}
使用反射获取它们,您可以传递可选参数到 `$attributes = $reflectionClass->getAttributes(
ContainerAttribute::class,
ReflectionAttribute::IS_INSTANCEOF
);
# 闭包
# 修饰
# Enums(枚举)
# 声明枚举 8.1
枚举内置于语言中:enum Status
{
case DRAFT;
case PUBLISHED;
case ARCHIVED;
}
# 枚举方法 8.1
枚举可以包含方法,也可以具有每个case的字符串或整数值:enum Status: int
{
case DRAFT = 1;
case PUBLISHED = 2;
case ARCHIVED = 3;
public function color(): string
{
return match($this)
{
Status::DRAFT => 'grey',
Status::PUBLISHED => 'green',
Status::ARCHIVED => 'red',
};
}
}
# 异常 8.0
引发异常现在是一个表达式,这意味着可以在更多位置抛出,例如短闭包或null并合运算符处
$error = fn($message) => throw new Error($message);
$input = $data['input'] ?? throw new Exception('Input not set');
你也不是必须再用一个变量去捕获异常:
try {
// …
} catch (SpecificException) {
throw new OtherException();
}
# Match 8.0
与 switch
, 类似,但使用强类型检查,无
break
关键字,组合臂, 它返回一个值:
$message = match ($statusCode) {
200, 300 => null,
400 => 'not found',
500 => 'server error',
default => 'unknown status code',
};
# 处理 null
# Null 合并 7.0
当属性为 null
时,使用 null 合并运算符提供回退(fallback):
$paymentDate = $invoice->paymentDate ?? Date::now();
它也可以嵌套:
$input = $data['few']['levels']['deep'] ?? 'foo';
7.4
可以使用 null 合并赋值运算符在原始变量为
null
时将值写入原始变量:
$temporaryPaymentDate = $invoice->paymentDate ??= Date::now();
// $invoice->paymentDate 现在也被设置
# Nullsafe(Null安全)运算符 8.0
可能返回null
的链式方法:
$invoice
->getPaymentDate()
?->format('Y-m-d');
nullsafe 运算符也可以被链接多次:
$object
?->methodA()
?->methodB()
?->methodC();
# 命名参数 8.0
按名称而不是位置传递参数:
setcookie(
name: 'test',
expires: time() + 60 * 60 * 2,
);
命名参数还支持数组展开:
$data = [
'name' => 'test',
'expires' => time() + 60 * 60 * 2,
];
setcookie(...$data);
# 性能优化
# 属性
# 构造函数属性提升 8.0
将构造函数参数加上public
, protected
或 private
参数,以使其得到提升:
class CustomerDTO
{
public function __construct(
public string $name,
public string $email,
public DateTimeImmutable $birth_date,
) {}
}
你仍然可以添加构造函数体,并合并提升属性和非提升属性:
class MyClass
{
public string $b;
public function __construct(
public string $a,
string $b,
) {
assert($this->a !== 'foo');
$this->b = $b;
}
}
# 在初始化器中使用new关键字 8.1
PHP 8.1 允许您在函数定义中使用 new 关键字作为默认参数,以及在注解参数和其他位置。class MyController {
public function __construct(
private Logger $logger = new NullLogger(),
) {}
}
这也意味着嵌套注解现在可以用:
#[Assert\All(
new Assert\NotNull,
new Assert\Length(max: 6),
)]
# 只读属性 8.1
属性可以标记为只读.class Offer
{
public readonly ?string $offerNumber = null;
public readonly Money $totalPrice;
一旦设置了只读属性,它就不能再更改了。
8.2
类可以是完全只读的:
readonly class Offer
{
public ?string $offerNumber = null;
public Money $totalPrice;
}
一个类的所有属性都将变为只读,动态添加属性是不可能的.
# 类型
# 内建类型
在 PHP 7.x 版本和 PHP 8 期间,添加了几种新的内置类型:
-
void
: 表明没有任何东西返回 7.1 -
static
: 表示当前类或其子类的返回类型 8.0 -
object
: 返回一个对象 7.2 -
mixed
: 任何类型 8.0
# 类型属性 7.4
向类属性添加类型:
class Offer
{
public ?string $offerNumber = null;
public Money $totalPrice;
}
谨防未初始化
状态,因为仅在读取属性时检查它,而不是在构造类时检查:
$offer = new Offer();
$offer->totalPrice; // Error
# 联合类型 8.0
将多个类型合并到一个联合类型中,这意味着任何输入都必须匹配给定类型中的一个:
interface Repository
{
public function find(int|string $id);
}
# DNF 类型 8.2
您可以创建交集类型的联合,这对于创建可为空的交集类型很有用:
public function url((WithId&WithSlug)|null $obj): string;