Залишилося всього кілька місяців до виходу PHP 8, і в цій версії дійсно є багато хорошого. В цій статті я хочу поділитися як зміниться код з приходом 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 7
У атрибутів є дві переваги:
- Код для налаштування підписників подій і обробників зібрано в одному місці, і мені не потрібно прокручувати файл до початку, щоб дізнатися, чи правильно налаштований підписник.
- Мені більше не потрібно турбуватися про написання та управлінні іменами методів у вигляді рядків (коли IDE не може їх автоматично заповнити, немає статичного аналізу помилок і не працює перейменування методів).
Але, на щастя PHP 8 розв'язує ці проблеми
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
Static замість doc-блоків
Це не така важливе зміна, але я стикаюся з цим кожен день. Я часто бачу, що мені все ще потрібні doc-блоки, коли треба вказати, що функція має зворотний тип static
.
Якщо в 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 (data transfer objects). Природно, я часто використовую 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.
Перерахування і 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 [ self::PENDING => 'orange', self::PAID => 'green', ][$this->value] ?? 'gray'; } }
PHP 7.4
Я б сказав, що для складніших умов вам краще використовувати патерн Стан, але є випадки, коли досить перерахування. Цей дивний синтаксис масиву вже є скороченням для більш громіздкого умовного виразу:
/** * @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
Об'єднання замість doc-блоків
Працює це аналогічно тому як було описано раніше типу static
що повертається функцією.
/** * @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
Оператор nullsafe
Якщо ви знайомі з оператором null coalescing, вам відомі його недоліки: він не працює з викликами методів. Тому мені часто були потрібні проміжні перевірки або відповідні для цієї мети функції фреймворків:
$startDate = $booking->getStartDate(); $dateAsString = $startDate ? $startDate->asDateTimeString() : null;
PHP 7.4
З появою оператора nullsafe я можу розв'язувати цю задачу набагато простіше.
$dateAsString = $booking->getStartDate()?->asDateTimeString();
PHP 8
А які нововведення в PHP 8 вважаєте важливими ви?
Джерело ENG: stitcher.io
Ще немає коментарів