PHP 8: código "Antes" y "Después" (comparación con PHP 7.4)





Quedan solo unos meses hasta que PHP 8 esté disponible, y realmente hay muchas cosas buenas en esta versión. Debajo del corte, le diremos cómo estas innovaciones ya han comenzado a cambiar el enfoque del autor para escribir código.



Suscriptores de eventos con atributos



Intentaré no abusar de los atributos, pero en el caso de configurar oyentes de eventos, por ejemplo, son muy útiles.



Recientemente he estado trabajando en sistemas en los que existía una gran cantidad de esta configuración. Tomemos un ejemplo:



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


Los



atributos de PHP 7 en PHP 8 tienen dos ventajas:



  • El código para configurar detectores y controladores de eventos se recopila en un solo lugar, y no tengo que desplazarme hasta el principio para ver si el detector está configurado correctamente.
  • Ya no necesito preocuparme por escribir y manipular nombres de métodos como cadenas (cuando el IDE no puede completarlos automáticamente, no hay un análisis estático de errores tipográficos y los métodos de cambio de nombre no funcionan).


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



Estático en lugar de bloques de documentos



Este no es un cambio tan grande, pero lo veo todos los días. A menudo encuentro que todavía necesito bloques de documentos cuando necesito especificar que una función tiene un tipo de retorno estático.



Si en PHP 7.4 necesitaba escribir:



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


PHP 7.4



Entonces es suficiente ahora:



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


PHP 8



DTO, pasando propiedades y argumentos con nombre



He escrito bastante sobre el uso del sistema de tipos PHP y el patrón DTO ( objetos de transferencia de datos ). Naturalmente, utilizo mucho DTO en mi propio código, así que puedes imaginar lo feliz que estoy de poder reescribir esto:



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



Aquí, eso es mejor:



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

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


PHP 8



Tenga en cuenta el uso de pasar las propiedades del constructor como parámetros con nombre. Sí, se pueden pasar mediante matrices con nombre y el operador Spread.



Enumeraciones y coincidencia



¿Está utilizando una enumeración con algunos métodos que devuelven un resultado en función del valor específico de la enumeración?



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



Yo diría que para condiciones más complejas es mejor usar el patrón State, pero hay casos en los que una enumeración es suficiente. Esta extraña sintaxis de matriz ya es una forma abreviada de una expresión condicional más engorrosa:



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



Pero en PHP 8 podemos usar match en su 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



Se une en lugar de bloques de documentos



Esto funciona de manera similar a lo que se describió anteriormente para el 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



Lanzar excepciones



Anteriormente, no podía usar throw en una expresión, lo que significaba que tenía que escribir, por ejemplo, las siguientes comprobaciones:



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

    // …
}


PHP 7.4



En PHP 8, throw se convirtió en una expresión, lo que significa que puede usarlo así:



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

    // …
}


PHP 8



Operador de seguridad nula



Si está familiarizado con el operador de fusión nula, conoce sus desventajas: no funciona con llamadas a métodos. Por lo tanto, a menudo necesitaba verificaciones intermedias o funciones de marco adecuadas para este propósito:



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


PHP 7.4



Con la introducción del operador nullsafe, puedo resolver este problema mucho más fácilmente.



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


PHP 8



¿Qué innovaciones en PHP 8 considera importantes?






Publicidad



Servidores para desarrollar y alojar sus proyectos. Cada servidor está conectado a un canal de 500 Megabit protegido contra ataques DDoS, es posible utilizar una red local de alta velocidad. Ofrecemos una amplia gama de planes de tarifas, cambio de tarifa en un clic. Panel de control del servidor muy conveniente y la capacidad de utilizar la API. ¡Date prisa para comprobarlo!






All Articles