PHP 8: código "Antes" e "Depois" (comparação com PHP 7.4)





Faltam apenas alguns meses para o lançamento do PHP 8, e realmente há muitas coisas boas neste lançamento. Em seguida, contaremos como essas inovações já começaram a mudar a abordagem do autor para escrever código.



Assinantes de eventos com atributos



Vou tentar não abusar dos atributos, mas no caso de configurar ouvintes de eventos, por exemplo, eles são muito úteis.



Recentemente, tenho trabalhado em sistemas onde havia muitas dessas configurações. Vamos dar um exemplo:



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
    { /* … */ }
}


Os



atributos do PHP 7 no PHP 8 têm duas vantagens:



  • O código para configurar ouvintes e manipuladores de eventos está em um só lugar, e não preciso rolar até o início para ver se o ouvinte está configurado corretamente.
  • Não preciso mais me preocupar em escrever e manipular nomes de métodos como strings (quando o IDE não consegue preenchê-los automaticamente, não há análise estática de erros de digitação e a renomeação de métodos não funciona).


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



Blocos estáticos em vez de doc



Não é uma grande mudança, mas vejo isso todos os dias. Freqüentemente, descubro que ainda preciso de blocos doc quando preciso especificar que uma função tem um tipo de retorno estático.



Se no PHP 7.4 eu precisava escrever:



/**
 * @return static
 */
public static function new()
{
    return new static();
}


PHP 7.4



Então é o suficiente agora:



public static function new(): static
{
    return new static();
}


PHP 8



DTO, passando propriedades e argumentos nomeados



Escrevi bastante sobre como usar o sistema de tipos PHP e o padrão DTO ( objetos de transferência de dados ). Naturalmente, eu uso muito DTOs em meu próprio código, então você pode imaginar como estou feliz por agora ser capaz de reescrever isso:



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



Aqui está melhor:



class CustomerData
{
    public function __construct(
        public string $name,
        public string $email,
        public int $age,
    ) {}
}

$data = new CustomerData(...$customerRequest->validated());


PHP 8



Observe o uso de passar propriedades do construtor como parâmetros nomeados. Sim, eles podem ser transmitidos usando matrizes nomeadas e o operador Spread.



Enumerações e correspondência



Você está usando um enum com alguns métodos que retornam um resultado dependendo do valor específico da enumeração?



/**
 * @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



Eu diria que para condições mais complexas é melhor usar o padrão State, mas há casos em que uma enumeração é suficiente. Esta estranha sintaxe de array já é uma abreviação para uma expressão condicional mais complicada:



/**
 * @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 - Alternativa



Mas no PHP 8 podemos usar match no lugar.



/**
 * @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



Ingressos em vez de blocos de documentos



Isso funciona de maneira semelhante ao que foi descrito anteriormente para o tipo de retorno estático.



/**
 * @param string|int $input
 *
 * @return string 
 */
public function sanitize($input): string;


PHP 7.4



public function sanitize(string|int $input): string;


PHP 8



Lançamento de exceções



Anteriormente, você não podia usar lançar uma expressão, o que significava que você tinha que escrever, por exemplo, estas verificações:



public function (array $input): void
{
    if (! isset($input['bar'])) {
        throw BarIsMissing::new();
    }
    
    $bar = $input['bar'];

    // …
}


PHP 7.4



No PHP 8, throw tornou-se uma expressão, o que significa que você pode usá-lo assim:



public function (array $input): void
{
    $bar = $input['bar'] ?? throw BarIsMissing::new();

    // …
}


PHP 8



Operador Nullsafe



Se você está familiarizado com o operador de coalescência nula, está ciente de suas desvantagens: ele não funciona com chamadas de método. Portanto, muitas vezes eu precisava de verificações intermediárias ou funções de estrutura adequadas para este propósito:



$startDate = $booking->getStartDate();
$dateAsString = $startDate ? $startDate->asDateTimeString() : null;


PHP 7.4



Com a introdução do operador nullsafe, posso resolver esse problema muito mais facilmente.



$dateAsString = $booking->getStartDate()?->asDateTimeString();


PHP 8



Quais inovações no PHP 8 você considera importantes?






Publicidade



Servidores para desenvolvimento e hospedagem de seus projetos. Cada servidor está conectado a um canal de 500 Megabit protegido de ataques DDoS, sendo possível utilizar uma rede local de alta velocidade. Oferecemos uma vasta gama de planos tarifários, alteração tarifária com um clique. Painel de controle do servidor muito conveniente e capacidade de usar a API. Apresse-se para verificar!






All Articles