PHP 8 - essayer de nouvelles fonctionnalités



PHP 8 est déjà au stade de la version candidate, la version RC 3 est sortie le 29 octobre et la version complète est prévue pour le 26 novembre. Il est donc temps de jeter un œil aux nouvelles fonctionnalités qui nous attendent dans PHP 8. Le calendrier des versions peut être consulté ici . Et le guide officiel pour la mise à jour vers une nouvelle version est ici .



Ajout de la prise en charge des types d'union ( RFC )



Le type union accepte des valeurs de divers autres types, pas seulement un.



<?php
declare(strict_types=1);
 
class Number {
    private int|float $number;
 
    public function setNumber(int|float $number): void {
        $this->number = $number;
    }
 
    public function getNumber(): int|float {
        return $this->number;
    }
}
 
/**
 * We can pass both floats or integer values
 * to the number object. Try passing a string.
 */
$number = new Number();
 
$number->setNumber(5);
 
dump($number->getNumber());
 
$number->setNumber(11.54);
 
dump($number->getNumber());
 
exit;


Ajout de WeakMap ( RFC )



Les mappages faibles vous permettent de créer des relations entre des objets et des valeurs arbitraires (ainsi que SplObjectStorage), tandis que les objets utilisés comme clés ne sont pas protégés du ramasse-miettes. Si le collecteur détruit un tel objet, il est simplement supprimé de la carte.


C'est une fonctionnalité très utile. Cela nous permet de penser encore moins aux fuites de mémoire dans notre code. Bien que cela ne devrait pas être un problème pour la plupart des développeurs PHP, cela vaut la peine de s'y intéresser lors de la création de processus longs, par exemple en utilisant ReactPHP. Avec WeakMaps, les références d'objet sont automatiquement collectées par le garbage collector lorsque l'objet devient indisponible.



Si vous faites de même avec un tableau, les références d'objet persisteront, conduisant à une fuite de mémoire.



<?php
declare(strict_types=1);
 
class FooBar {
    public WeakMap $cache;
    
    public function __construct() {
      $this->cache = new WeakMap();
    }
 
    public function getSomethingWithCaching(object $obj) {
        return $this->cache[$obj] ??= $this->computeSomethingExpensive($obj);
    }
    
    public function computeSomethingExpensive(object $obj) {
    dump("I got called");
    return rand(1, 100);
    }
}
 
$cacheObject = new stdClass;
 
$obj = new FooBar;
// "I got called" only will be printed once
$obj->getSomethingWithCaching($cacheObject);
$obj->getSomethingWithCaching($cacheObject);
 
dump(count($obj->cache));
 
// When unsetting our object, the WeakMap frees up memory
unset($cacheObject);
 
dump(count($obj->cache));
 
exit;


Nouvelle exception ValueError



PHP 8 introduit une nouvelle classe d'exception intégrée ValueError. Il se complète \Exception. PHP lève cette exception à chaque fois que vous passez une valeur du type correct à une fonction, mais elle ne peut pas être utilisée dans cette opération. Auparavant, un avertissement était émis dans de tels cas. Exemples:



<?php
declare(strict_types=1);
 
/**
 * We pass an array to array_rand,
 * which is of the correct type. But
 * array_rand expects non-empty arrays.
 *
 * This throws a ValueError exception.
 */
array_rand([], 0);
 
/**
 * The depth argument for json_decode is a
 * valid integer, but it must be greater than 0
 */
json_decode('{}', true, -1);


Lors de la définition des fonctions, vous pouvez utiliser un argument variadique



N'importe quel nombre de paramètres de fonction peut maintenant être remplacé par un argument variadique si leurs types sont compatibles. Par exemple, le code suivant est incorrect:


<?php
declare(strict_types=1);
 
class A {
    public function method(int $many, string $parameters, $here) {
 
    }
}
class B extends A {
    public function method(...$everything) {
        dd($everything);
    }
}
 
$b = new B();
$b->method('i can be overwritten!');
exit;


Type de retour statique ( RFC )



Le type de retour statique peut désormais être utilisé pour déterminer si une méthode renvoie la classe pour laquelle la méthode a été appelée, même si elle a été héritée (liaison statique tardive).



<?php
declare(strict_types=1);
 
class Test {
    public function doWhatever(): static {
        // Do whatever.
        return $this;
    }
}
 
exit;


Nom de classe d'objet littéral ( RFC )



Vous pouvez maintenant récupérer le nom de classe d'un objet à l'aide de $object::class. Le résultat sera le même qu'avec get_class($object).



<?php
declare(strict_types=1);
 
auth()->loginUsingId(1);
 
dump(auth()->user()::class);
 
// Or with a temporary variable
$user = auth()->user();
 
dump($user::class);
exit;


Paramètres de syntaxe variable ( RFC )



Newet instanceofpeut maintenant être utilisé avec des expressions arbitraires: new ()(...$args)et $obj instanceof ().



<?php
declare(strict_types=1);
 
class Foo {}
class Bar {}
 
 
$class = new (collect(['Foo', 'Bar'])->random());
 
dd($class);
 
exit;


Interface à cordes ( RFC )



PHP 8 introduit une nouvelle interface Stringablequi est ajoutée automatiquement dès qu'une classe implémente une méthode __toString. Vous n'avez pas besoin d'implémenter explicitement cette interface.



<?php
declare(strict_types=1);
 
class Foo {
    public function __toString() {
        return 'I am a class';
    }
}
 
$obj = new Foo;
dump($obj instanceof Stringable);
 
exit;


Les traits peuvent désormais définir des méthodes privées abstraites ( RFC )



<?php
declare(strict_types=1);
 
 
trait MyTrait {
    abstract private function neededByTheTrait(): string;
 
    public function doSomething() {
        return strlen($this->neededByTheTrait());
    }
}
 
class TraitUser {
    use MyTrait;
 
    // This is allowed:
    private function neededByTheTrait(): string { }
 
    // This is forbidden (incorrect return type)
    // private function neededByTheTrait(): stdClass { }
 
    // This is forbidden (non-static changed to static)
    // private static function neededByTheTrait(): string { }
}
 
exit;


throw peut maintenant être utilisé comme une expression ( RFC )



L'expression throwpeut maintenant être utilisée là où seules les expressions sont autorisées: dans les fonctions fléchées, les opérateurs de fusion, les opérateurs conditionnels ternaires (ternaire / elvis).



<?php
declare(strict_types=1);
 
$callable = fn() => throw new Exception();
 
$nullableValue = null;
 
// $value is non-nullable.
$value = $nullableValue ?? throw new \InvalidArgumentException();
 
 
exit;


La virgule pendante ( RFC ) facultative est désormais autorisée dans les paramètres de liste



Par analogie avec la virgule suspendue dans les tableaux, vous pouvez maintenant la définir dans les paramètres de la liste.



<?php
declare(strict_types=1);
 
function method_with_many_arguments(
    $a, 
    $b,
    $c,
    $d,
) {
    dump("this is valid syntax");
}
 
method_with_many_arguments(
    1,
    2,
    3,
    4,
);
 
exit;


Obtention d'exceptions sans stockage dans une variable ( RFC )



Vous pouvez maintenant écrire catch ()pour intercepter les exceptions sans les stocker dans une variable.



<?php
declare(strict_types=1);
 
$nullableValue = null;
 
try {
    $value = $nullableValue ?? throw new \InvalidArgumentException();
} catch (\InvalidArgumentException) {
    dump("Something went wrong");
}
 
 
exit;


Ajout de la prise en charge du type mixte ( RFC )



PHP 8 introduit un nouveau type appelé mixed. Il peut être équivalent aux types array, bool, callable, int, float, null, object, resource, string.



<?php
declare(strict_types=1);
 
function debug_function(mixed ...$data) {
    dump($data);
}
 
debug_function(1, 'string', []);
 
exit;


Ajout de la prise en charge des attributs



Il existe plusieurs suggestions pour implémenter des attributs en PHP 8:





C'est l'un des plus gros changements de PHP 8. Ce n'est peut-être pas si facile à comprendre au début. En bref, les attributs vous permettent d'ajouter des métadonnées aux fonctions PHP, aux paramètres, aux classes, etc. Ces métadonnées peuvent ensuite être récupérées par programme. Si en PHP 7 ou inférieur vous avez besoin d'analyser des doclocks, les attributs vous aideront à accéder à ces informations profondément intégrées dans PHP lui-même.



Pour clarifier les choses, imaginez que vous souhaitez que vos utilisateurs puissent ajouter un middleware à un contrôleur de classe ou de méthode à l'aide d'un attribut.



<?php
declare(strict_types=1);
// First, we need to define the attribute. An Attribute itself is just a plain PHP class, that is annotated as an Attribute itself.
 
#[Attribute]
class ApplyMiddleware
{
    public array $middleware = [];
 
    public function __construct(...$middleware) {
        $this->middleware = $middleware;
    }
}
 
// This adds the attribute to the MyController class, with the "auth" middleware as an argument.
 
#[ApplyMiddleware('auth')]
class MyController
{
    public function index() {}
}
 
// We can then retrieve all ApplyMiddleware attributes on our class using reflection
// And read the given middleware arguments.
 
$reflectionClass = new ReflectionClass(MyController::class);
 
$attributes = $reflectionClass->getAttributes(ApplyMiddleware::class);
 
foreach ($attributes as $attribute) {
    $middlewareAttribute = $attribute->newInstance();
    dump($middlewareAttribute->middleware);
}
 
exit;


Ajout de la prise en charge de la transmission des propriétés du constructeur ( RFC )



Il est proposé d'ajouter une syntaxe simple pour combiner le constructeur avec la définition de propriété:



<?php
declare(strict_types=1);
 
class User {
    public function __construct(
        public int $id,
        public string $name,
    ) {}
}
 
$user = new User(1, 'Marcel');
 
dump($user->id);
dump($user->name);
 
exit;


Ajout de la prise en charge de l'expression de correspondance ( RFC )



Il est proposé d'ajouter une nouvelle expression matchsimilaire switch, uniquement avec une sémantique plus sûre et la possibilité de renvoyer des valeurs.



<?php
declare(strict_types=1);
 
echo match (1) {
    0 => 'Foo',
    1 => 'Bar',
    2 => 'Baz',
};
 
exit;


Ajout de la prise en charge de l'opérateur nullsafe (? ->) ( RFC )



Lorsque le résultat du côté gauche de l'opérateur est nul, l'exécution de la chaîne entière est arrêtée et son résultat est défini sur null. Sinon, la chaîne se comporte comme un opérateur normal ->.


<?php
declare(strict_types=1);
 
class User {
    public function getAddress() {}
}
 
$user = new User();
 
$country = $user?->getAddress()?->country?->iso_code;
 
dump($country);
 
exit;


Ajout de la prise en charge des arguments nommés ( RFC )



La dénomination vous permet de transmettre des arguments à une fonction en fonction du nom du paramètre et non de sa position. Autrement dit, les valeurs des arguments deviennent auto-documentées et les arguments ne dépendent plus de l'ordre d'énumération, vous pouvez donc ignorer arbitrairement les valeurs par défaut.


<?php
declare(strict_types=1);
 
array_fill(start_index: 0, num: 100, value: 50);
 
exit;



All Articles