Undefined


Migration vers PHP 8

PHP 8 est sorti depuis maintenant quelques jours, j'avais suivi les changements et je suis content de pouvoir utiliser pour la première fois cette nouvelle version.

Pour tester cette version j'ai repris un projet que j'avais présenté précédemment : Netflix data. L'objectif du projet est d'extraire des statistiques personnelles des données Netflix.

Tout d'abord pour passer en PHP 8 j'ai changé le Dockerfile :

- FROM php:7.4-cli
+ FROM php:8.0-cli

Après un rebuild du projet j'ai pu mettre à jour mon composer.json :

-    "php": "^7.4",
-    "symfony/serializer": "^5.1",
-    "symfony/console": "^5.1",
-    "symfony/property-access": "^5.1",
-    "symfony/yaml": "^5.1",
+    "php": "^8.0",
+    "symfony/serializer": "^5.2",
+    "symfony/console": "^5.2",
+    "symfony/property-access": "^5.2",

On remarquera la suppression de symfony/yaml un paquet que j'utilisais pour lire les métadonnées utiles au mapping lors de la dénormalisation de mes entités depuis les fichiers CSV.

Depuis PHP 8 nous avons des attributs pour gérer les métadonnées : Attributes. Et grâce au travail qui a été fait sur les dernières versions de Symfony nous pouvons donc changer notre fichier de métadonnées YAML :

App\Model\ViewingTime:
    attributes:
        profileName: "Profile Name"
        startTime: "Start Time"
        duration: "Duration"
        title: "Title"

Pour fournir ces informations directement dans notre entité :

class ViewingActivity extends Model
{
    #[SerializedName("Profile Name")]
    public string $profileName;

    #[SerializedName("Start Time")]
    public string $startTime;

    #[SerializedName("Duration")]
    public string $duration;

    #[SerializedName("Title")]
    public string $title;

    //...
}

Il s'agit d'un remplaçant direct aux annotations PHP que l'on pouvait utiliser dans les anciennes versions de PHP mais qui n'était pas un fonctionnement prévu par PHP. En effet il est possible maintenant d'utiliser les classes de réflexion pour lire ces métadonnées sans utiliser une dépendance tierce.

Voyons d'ailleurs comment utiliser en modifiant la manière de récupérer le fichier associé à une entité. Dans la version précédente, par simplicité, j'avais une variable statique qui contenait directement le chemin vers le fichier CSV associé à l'entité :

class ViewingActivity extends Model
{
    static string $file = "Content_Interaction/ViewingActivity.csv";

    //...
}

Dans cette version PHP 8, j'ai utilisé un attribut sur la classe :

#[FileModel(filename: "Content_Interaction/ViewingActivity.csv")]
class ViewingActivity extends Model
{
    //...
}

Pour fonctionner nous avons besoin de déclarer une classe marquée comme Attribute, ici FileModel avec les propriétés que l'on a besoin.

#[Attribute]
class FileModel
{
    public function __construct(public string $filename) {}
}

On peut noter l'utilisation du système de promotion de propriété : Constructor property promotion

Enfin, on peut récupérer les informations de cet attribut va notre classe de réflexion :

class Model
{
    public static function load(): array
    {
        $attributes = (new \ReflectionClass(static::class))->getAttributes(FileModel::class);

        if (empty($attributes)) {
            throw new \LogicException(sprintf("You must add a '%s' attribute on class '%s'", FileModel::class, static::class));
        }

        /** @var FileModel $fileModel */
        $fileModel = $attributes[0]?->newInstance();

        //...
    }
}

Là encore une fonctionnalité utile avec le Nullsafe operator : ?->newInstance()

Nous avons donc getAttributes qui permet de récupérer les attributs d'une classe (on peut préciser le type que l'on cherche) et la méthode newInstance pour récupérer une instance de notre classe d'attributs.

Il y a encore tout un tas d'évolution bien pratique qui rend l'expérience développeur plus agréable et j'attends avec impatience les prochaines versions de PHP8.

Les sources du projet sont disponibles sur GitHub : github.com/adrien-chinour/netflix-data.