PHP 8推出还剩几个月,而且此发行版中确实有很多不错的东西。在精简版下,我们将告诉您这些创新如何开始改变作者编写代码的方法。
具有属性的事件订阅者
我将尽量不要过度使用属性,但是例如在设置事件侦听器的情况下,它们非常有用。
最近,我一直在研究存在很多此类设置的系统。让我们举个例子:
class CartsProjector implements Projector
{
use ProjectsEvents;
protected array $handlesEvents = [
CartStartedEvent::class => 'onCartStarted',
CartItemAddedEvent::class => 'onCartItemAdded',
CartItemRemovedEvent::class => 'onCartItemRemoved',
CartExpiredEvent::class => 'onCartExpired',
CartCheckedOutEvent::class => 'onCartCheckedOut',
CouponAddedToCartItemEvent::class => 'onCouponAddedToCartItem',
];
public function onCartStarted(CartStartedEvent $event): void
{ /* … */ }
public function onCartItemAdded(CartItemAddedEvent $event): void
{ /* … */ }
public function onCartItemRemoved(CartItemRemovedEvent $event): void
{ /* … */ }
public function onCartCheckedOut(CartCheckedOutEvent $event): void
{ /* … */ }
public function onCartExpired(CartExpiredEvent $event): void
{ /* … */ }
public function onCouponAddedToCartItem(CouponAddedToCartItemEvent $event): void
{ /* … */ }
}
PHP
8中的PHP 7属性具有两个优点:
- 设置事件侦听器和处理程序的代码放在一个地方,我不必滚动到开头即可查看侦听器的设置是否正确。
- 我不再需要担心以字符串形式编写和处理方法名称(当IDE无法自动完成它们时,就不会对输入错误进行静态分析,并且方法的重命名也不起作用)。
class CartsProjector implements Projector
{
use ProjectsEvents;
@@SubscribesTo(CartStartedEvent::class)
public function onCartStarted(CartStartedEvent $event): void
{ /* … */ }
@@SubscribesTo(CartItemAddedEvent::class)
public function onCartItemAdded(CartItemAddedEvent $event): void
{ /* … */ }
@@SubscribesTo(CartItemRemovedEvent::class)
public function onCartItemRemoved(CartItemRemovedEvent $event): void
{ /* … */ }
@@SubscribesTo(CartCheckedOutEvent::class)
public function onCartCheckedOut(CartCheckedOutEvent $event): void
{ /* … */ }
@@SubscribesTo(CartExpiredEvent::class)
public function onCartExpired(CartExpiredEvent $event): void
{ /* … */ }
@@SubscribesTo(CouponAddedToCartItemEvent::class)
public function onCouponAddedToCartItem(CouponAddedToCartItemEvent $event): void
{ /* … */ }
}
PHP 8
静态而不是文档块
这不是很大的变化,但我每天都看到。我经常发现当我需要指定一个函数具有静态返回类型时,我仍然需要文档块。
如果在PHP 7.4中,我需要编写:
/**
* @return static
*/
public static function new()
{
return new static();
}
PHP 7.4
然后就足够了:
public static function new(): static
{
return new static();
}
PHP 8
DTO,传递属性和命名参数
我已经写了很多有关使用PHP类型系统和DTO(数据传输对象)模式的文章。自然,我在自己的代码中经常使用DTO,所以您可以想象我现在能够重写此代码多么高兴:
class CustomerData extends DataTransferObject
{
public string $name;
public string $email;
public int $age;
public static function fromRequest(
CustomerRequest $request
): self {
return new self([
'name' => $request->get('name'),
'email' => $request->get('email'),
'age' => $request->get('age'),
]);
}
}
$data = CustomerData::fromRequest($customerRequest);
PHP 7.4
在此更好:
class CustomerData
{
public function __construct(
public string $name,
public string $email,
public int $age,
) {}
}
$data = new CustomerData(...$customerRequest->validated());
PHP 8
请注意,将传递构造函数属性用作命名参数。是的,可以使用命名数组和Spread运算符传递它们。
枚举和匹配
您是否将枚举与一些根据枚举的特定值返回结果的方法一起使用?
/**
* @method static self PENDING()
* @method static self PAID()
*/
class InvoiceState extends Enum
{
private const PENDING = 'pending';
private const PAID = 'paid';
public function getColour(): string
{
return [
self::PENDING => 'orange',
self::PAID => 'green',
][$this->value] ?? 'gray';
}
}
PHP 7.4
我要说的是,对于更复杂的条件,最好使用State模式,但是在某些情况下枚举就足够了。这种奇怪的数组语法已经是更麻烦的条件表达式的简写形式:
/**
* @method static self PENDING()
* @method static self PAID()
*/
class InvoiceState extends Enum
{
private const PENDING = 'pending';
private const PAID = 'paid';
public function getColour(): string
{
if ($this->value === self::PENDING) {
return 'orange';
}
if ($this->value === self::PAID) {
return 'green'
}
return 'gray';
}
}
PHP 7.4-替代方法
但是在PHP 8中,我们可以改用match。
/**
* @method static self PENDING()
* @method static self PAID()
*/
class InvoiceState extends Enum
{
private const PENDING = 'pending';
private const PAID = 'paid';
public function getColour(): string
{
return match ($this->value) {
self::PENDING => 'orange',
self::PAID => 'green',
default => 'gray',
};
}
PHP 8
联接而不是文档块
这的工作方式与先前针对静态返回类型所述的方式类似。
/**
* @param string|int $input
*
* @return string
*/
public function sanitize($input): string;
PHP 7.4
public function sanitize(string|int $input): string;
PHP 8
抛出异常
以前,您不能在表达式中使用throw,这意味着您必须编写例如以下检查:
public function (array $input): void
{
if (! isset($input['bar'])) {
throw BarIsMissing::new();
}
$bar = $input['bar'];
// …
}
PHP 7.4
在PHP 8中,throw成为一个表达式,这意味着您可以像这样使用它:
public function (array $input): void
{
$bar = $input['bar'] ?? throw BarIsMissing::new();
// …
}
PHP 8
空安全运算符
如果您熟悉空合并运算符,那么您会知道它的缺点:它不适用于方法调用。因此,我经常需要适合于此目的的中间检查或框架功能:
$startDate = $booking->getStartDate();
$dateAsString = $startDate ? $startDate->asDateTimeString() : null;
PHP 7.4
通过引入nullsafe运算符,我可以更轻松地解决此问题。
$dateAsString = $booking->getStartDate()?->asDateTimeString();
PHP 8
您认为PHP 8中的哪些创新很重要?
广告
用于开发和托管项目的服务器。每个服务器都连接到受DDoS攻击保护的500兆通道,可以使用高速本地网络。我们提供多种关税计划,一键更改关税。非常方便的服务器控制面板和使用API的能力。快点检查!