PHP 8: code "Avant" et "Après" (comparaison avec PHP 7.4)





Il ne reste que quelques mois avant la sortie de PHP 8, et il y a vraiment beaucoup de bonnes choses dans cette version. Sous la coupe, nous vous dirons comment ces innovations ont déjà commencé à changer l'approche de l'auteur en matière d'écriture de code.



Abonnés à l'événement avec attributs



J'essaierai de ne pas abuser des attributs, mais dans le cas de la configuration des écouteurs d'événements, par exemple, ils sont très utiles.



Récemment, j'ai travaillé sur des systèmes où il y avait beaucoup de tels paramètres. Prenons un exemple:



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


Les



attributs PHP 7 dans PHP 8 présentent deux avantages:



  • Le code de configuration des écouteurs et des gestionnaires d'événements se trouve au même endroit et je n'ai pas besoin de faire défiler jusqu'au début pour voir si l'écouteur est configuré correctement.
  • Je n'ai plus besoin de m'inquiéter de l'écriture et de la manipulation des noms de méthodes sous forme de chaînes (lorsque l'EDI ne peut pas les compléter automatiquement, il n'y a pas d'analyse statique des fautes de frappe et le changement de nom des méthodes ne fonctionne pas).


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



Blocs statiques au lieu de doc



Ce n'est pas un si grand changement, mais je le vois tous les jours. Je trouve souvent que j'ai toujours besoin de blocs doc lorsque je dois spécifier qu'une fonction a un type de retour statique.



Si en PHP 7.4 j'avais besoin d'écrire:



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


PHP 7.4



Alors ça suffit maintenant:



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


PHP 8



DTO, passer des propriétés et des arguments nommés



J'ai beaucoup écrit sur l'utilisation du système de type PHP et du modèle DTO ( objets de transfert de données ). Naturellement, j'utilise beaucoup les DTO dans mon propre code, vous pouvez donc imaginer à quel point je suis heureux de pouvoir maintenant réécrire ceci:



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



Ici, c'est mieux:



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

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


PHP 8



Notez l'utilisation de la transmission des propriétés du constructeur en tant que paramètres nommés. Oui, ils peuvent être passés à l'aide de tableaux nommés et de l'opérateur Spread.



Énumérations et correspondance



Utilisez-vous une énumération avec certaines méthodes qui retournent un résultat en fonction de la valeur spécifique de l'énumération?



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



Je dirais que pour des conditions plus complexes, il vaut mieux utiliser le modèle State, mais il y a des cas où une énumération est suffisante. Cette étrange syntaxe de tableau est déjà un raccourci pour une expression conditionnelle plus lourde:



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



Mais en PHP 8, nous pouvons utiliser match à la place.



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



Joint au lieu de blocs doc



Cela fonctionne de la même manière que ce qui a été décrit précédemment pour le type de retour statique.



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


PHP 7.4



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


PHP 8



Lancer des exceptions



Auparavant, vous ne pouviez pas utiliser throw dans une expression, ce qui signifiait que vous deviez écrire, par exemple, les vérifications suivantes:



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

    // …
}


PHP 7.4



En PHP 8, throw est devenu une expression, ce qui signifie que vous pouvez l'utiliser comme ceci:



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

    // …
}


PHP 8



Opérateur Nullsafe



Si vous êtes familier avec l'opérateur de fusion nul, vous êtes conscient de ses inconvénients: il ne fonctionne pas avec les appels de méthode. Par conséquent, j'avais souvent besoin de vérifications intermédiaires ou de fonctions cadre adaptées à cet effet:



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


PHP 7.4



Avec l'introduction de l'opérateur nullsafe, je peux résoudre ce problème beaucoup plus facilement.



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


PHP 8



Quelles innovations de PHP 8 considérez-vous comme importantes?






La publicité



Des serveurs pour développer et héberger vos projets. Chaque serveur est connecté à un canal de 500 Mégabits protégé des attaques DDoS, il est possible d'utiliser un réseau local haut débit. Nous vous proposons une large gamme de plans tarifaires, le changement tarifaire en un clic. Panneau de contrôle serveur très pratique et possibilité d'utiliser l'API. Dépêchez-vous de vérifier!






All Articles