T: / Corrigés des challenges / PHP
Utilisation des enums en implémentant une interface pour bien les structurer.
Ce corrigé est la « refactorisation POO » du premier corrigé du Pôle Express, qui permettait de découvrir l’utilisation de la structure match. match étant particulièrement utilisé dans les enums, je propose donc d’utiliser cette structure pour résoudre le challenge avec un code PHP orienté objet beaucoup plus structuré
Et j’en profite pour créer une interface et faire en sorte que mes enums implémentent cette interface pour bien les structurer.
Au programme :
Dans le challenge, 3 éléments font varier la température : le type de chocolat, l’épice, et un évènement particulier. Je vais donc créer une interface pour préciser qu’il y aura toujours une méthode qui fait varier la température. Cette méthode prend en paramètre une température initiale, et renvoie une température modifiée :
interface TemperatureModifier {
public function modifyTemperature(int $temperature): int;
}
Voici l’enum pour les types de chocolat :
enum ChocolateType: string implements TemperatureModifier
{
case NOIR = 'noir';
case AU_LAIT = 'au_lait';
case BLANC = 'blanc';
case MELANGE = 'melange';
public function modifyTemperature(int $temperature): int
{
return match($this) {
self::NOIR => $temperature + 5,
self::AU_LAIT => $temperature + 10,
self::BLANC => $temperature + 15,
self::MELANGE => $temperature + 12,
};
}
}
Un peu d’explications :
Les 2 autres enums ont des structures similaires et peuvent être retrouvés sur Github.
Je décide de structurer chaque commande dans une classe « Order » :
class Order
{
private function __construct(
private int $temperature,
public ChocolateType $chocolateType,
public SpiceType $spiceType,
public ?Event $event,
) { }
public static function createFromText(string $informations): Order
{
$data = explode(',', $informations);
$temperature = (int) $data[0];
$chocolateType = ChocolateType::from($data[1]);
$spiceType = SpiceType::from($data[2]);
$event = isset($data[3]) ? Event::from($data[3]) : null;
return new self($temperature, $chocolateType, $spiceType, $event);
}
public function modifyTemperature(): void
{
$this->temperature = $this->chocolateType->modifyTemperature($this->temperature);
$this->temperature = $this->spiceType->modifyTemperature($this->temperature);
if (! is_null($this->event)) {
$this->temperature = $this->event->modifyTemperature($this->temperature);
}
}
public function getTemperature(): int
{
return $this->temperature;
}
}
Un peu d’explications :
Et voici le programme principal, forcément beaucoup + concis que dans la première version du corrigé !
$total = 0;
foreach ($orders as $orderInformations) {
$order = Order::createFromText($orderInformations);
$order->modifyTemperature();
$total += $order->getTemperature();
}
$average = ceil($total / count($orders));
Un peu d’explications :
Le code complet est disponible sur Github.
Retrouve aussi un autre corrigé qui utilise les enums en PHP.
On va créer un fichier pour tester l’enum ChocolateType, qui est présent + haut dans le corrigé. Je vais donc vérifier que chaque cas est bien respecté :
test('La température augmente de 5 pour le chocolat noir', function () {
$temperature = ChocolateType::NOIR->modifyTemperature(0);
expect($temperature)->toBe(5);
});
test('La température augmente de 10 pour le chocolat au lait', function () {
$temperature = ChocolateType::AU_LAIT->modifyTemperature(0);
expect($temperature)->toBe(10);
});
test('La température augmente de 15 pour le chocolat blanc', function () {
$temperature = ChocolateType::BLANC->modifyTemperature(0);
expect($temperature)->toBe(15);
});
test('La température augmente de 12 pour le mélange de chocolat', function () {
$temperature = ChocolateType::MELANGE->modifyTemperature(0);
expect($temperature)->toBe(12);
});
Avec ces tests, je m’assure donc que chaque cas est géré correctement. Mais si je rajoute un cas dans mon enum, sans le gérer dans modifyTemperature, ni mon code, ni mon IDE, et ni mes tests ne m’indiqueront aucune erreur. Et c’est exactement ce que je cherche à faire, à ce que mes tests me préviennent de mon oubli. Voici une approche :
test('Tous les cas sont bien paramétrés dans modifyTemperature', function () {
$initialTemperature = 10; // Une température initiale arbitraire
foreach (ChocolateType::cases() as $chocolateType) {
$chocolateType->modifyTemperature($initialTemperature);
}
$this->assertTrue(true);
});
Un peu d’explications :
On se rapproche ici de la notion de TDD : Test Driven Development. Ce sont mes tests en erreur qui vont m’indiquer quelles sont les portions de code que je dois encore travailler ! Pratique !
Other content to discover