Service de location de véhicules
Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy. Leçon 91 sur 91.
Défi
FacileConstruisons un système de service de location de véhicules qui gère une flotte de véhicules, suit les locations des clients et calcule les tarifs en fonction du type de véhicule. Ce défi complet réunit l'héritage, les interfaces, l'encapsulation et le pattern State afin de créer une application réaliste de gestion de locations.
Vous organiserez votre code sur sept fichiers :
VehicleState.php: définissez une interfaceVehicleStatequi représente les différents états dans lesquels un véhicule peut se trouver. Incluez deux méthodes :getStatus(): stringetcanRent(): bool. Créez ensuite trois classes qui implémentent cette interface :AvailableState: renvoie"Available"ettrueRentedState: renvoie"Rented"etfalseMaintenanceState: renvoie"Maintenance"etfalse
Vehicle.php: incluez le fichier VehicleState. Créez une classe abstraiteVehicleavec la promotion de constructeur pourlicensePlate(string, public readonly),brand(string, public readonly) etdailyRate(float, protected). Stockez l'état actuel dans une propriété privée, avecAvailableStatecomme valeur par défaut. Implémentez :getState(): VehicleState: renvoie l'état actuelsetState(VehicleState $state): void: modifie l'étatgetStatus(): string: délègue àgetStatus()de l'étatcanRent(): bool: délègue àcanRent()de l'étatabstract calculateCost(int $days): float: chaque type de véhicule effectue le calcul différemmentgetType(): string: renvoie le nom de la classe avecstatic::class
Vehicles.php: incluez le fichier Vehicle. Créez trois classes concrètes de véhicules :Car: étend Vehicle ;calculateCost()renvoiedailyRate * daysMotorcycle: étend Vehicle ;calculateCost()renvoiedailyRate * days * 0.8(remise de 20 %)Van: étend Vehicle avec un paramètre supplémentaire$mileageRate(float) ;calculateCost(int $days, int $miles = 0)renvoie(dailyRate * days) + (mileageRate * miles)
Customer.php: créez une classeCustomeravec la promotion de constructeur pourid(int, public readonly) etname(string, public readonly). Suivez l'historique des locations dans un tableau privé. Implémentez :addRental(string $vehiclePlate, float $cost): void: ajoute une location à l'historiquegetRentalCount(): int: renvoie le nombre de locationsgetTotalSpent(): float: renvoie la somme de tous les coûts de location
Rental.php: incluez les fichiers Vehicle et Customer. Créez une classeRentalqui associe un client à un véhicule. Utilisez la promotion de constructeur pourcustomer(Customer, public readonly),vehicle(Vehicle, public readonly),days(int, private) et éventuellementmiles(int, private, valeur par défaut 0). Implémentez :calculateTotal(): float: si le véhicule est un Van, transmettez miles àcalculateCost(); sinon, transmettez uniquement dayscomplete(): string: calcule le total, l'ajoute à l'historique du client, définit l'état du véhicule sur AvailableState et renvoie"Rental completed: $[total]"(avec 2 décimales)
RentalService.php: incluez les fichiers Rental et Vehicles. Créez une classeRentalServicequi gère la flotte. Stockez les véhicules dans un tableau privé indexé par plaque d'immatriculation. Implémentez :addVehicle(Vehicle $vehicle): void: ajoute le véhicule à la flottefindVehicle(string $plate): ?Vehicle: renvoie le véhicule ou nullgetAvailableVehicles(): array: renvoie les véhicules pour lesquelscanRent()vaut truerentVehicle(Customer $customer, string $plate, int $days, int $miles = 0): string|Rental: si le véhicule est introuvable, renvoie"Vehicle not found"; s'il n'est pas disponible, renvoie"Vehicle is not available"; sinon, définit l'état du véhicule sur RentedState et renvoie un nouvel objet RentalsetMaintenance(string $plate): string: définit l'état du véhicule sur MaintenanceState ; renvoie"[plate] set to maintenance"ou"Vehicle not found"
main.php: incluez les fichiers RentalService et Customer. Vous recevrez trois entrées : les données de la flotte (JSON), les données du client (JSON) et les opérations (JSON).Format JSON de la flotte :
[{"type": "car", "plate": "CAR-001", "brand": "Toyota", "rate": 50}, {"type": "van", "plate": "VAN-001", "brand": "Ford", "rate": 80, "mileage_rate": 0.25}]Format JSON du client :
{"id": 1, "name": "Alice"}Format JSON des opérations :
[{"op": "available"}, {"op": "rent", "plate": "CAR-001", "days": 3}, {"op": "complete", "plate": "CAR-001"}, {"op": "maintenance", "plate": "VAN-001"}, {"op": "customer_stats"}]Créez le service de location, ajoutez tous les véhicules à la flotte et créez le client. Suivez les locations actives par plaque d'immatriculation. Traitez chaque opération :
"available": affichez"Available vehicles: [count]""rent": louez le véhicule ; en cas de succès, stockez le Rental et affichez"Rented [plate] for [days] days"; s'il s'agit d'un Van, incluez miles depuis l'opération ; sinon, affichez le message d'erreur"complete": finalisez la location enregistrée pour cette plaque ; affichez le résultat"maintenance": affichez le résultat desetMaintenance()"status": affichez"[plate]: [status]"pour la plaque indiquée"customer_stats": affichez"[name]: [count] rentals, $[total] spent"(avec 2 décimales)
Affichez chaque résultat sur une nouvelle ligne.
Ce système montre comment le pattern State gère élégamment la disponibilité des véhicules sans conditions complexes, comment l'héritage crée une hiérarchie claire de véhicules avec une tarification polymorphe et comment l'encapsulation protège l'intégrité des données de location tout au long du processus.
Essayez vous-même
<?php
require_once 'RentalService.php';
require_once 'Customer.php';
// Lire les entrées
$fleetJson = trim(fgets(STDIN));
$customerJson = trim(fgets(STDIN));
$operationsJson = trim(fgets(STDIN));
// Analyser les données JSON
$fleetData = (array)json_decode($fleetJson, true);
$customerData = (array)json_decode($customerJson, true);
$operations = (array)json_decode($operationsJson, true);
// TODO: Créer une instance de RentalService
// TODO: Ajouter tous les véhicules à la flotte selon le type :
// - "car" -> new Car(plate, brand, rate)
// - "motorcycle" -> new Motorcycle(plate, brand, rate)
// - "van" -> new Van(plate, brand, rate, mileage_rate)
// TODO: Créer une instance Customer à partir de customerData
// TODO: Créer un tableau pour suivre les locations actives par plaque
$activeRentals = [];
// TODO: Traiter chaque opération et afficher les résultats :
// - "available": Print "Available vehicles: [count]"
// - "rent": Louer le véhicule, stocker Rental en cas de succès, afficher le résultat
// - "complete": Terminer la location, afficher le résultat
// - "maintenance": Définir la maintenance, afficher le résultat
// - "status": Afficher "[plate]: [status]"
// - "customer_stats": Afficher "[name]: [count] rentals, $[total] spent"
foreach ($operations as $op) {
$operation = (array)$op;
$opType = $operation['op'];
// TODO: Gérer chaque type d'opération
switch ($opType) {
case 'available':
// TODO: Print available vehicle count
break;
case 'rent':
// TODO: Louer le véhicule et afficher le résultat
break;
case 'complete':
// TODO: Terminer la location et afficher le résultat
break;
case 'maintenance':
// TODO: Définir la maintenance et afficher le résultat
break;
case 'status':
// TODO: Afficher le statut du véhicule
break;
case 'customer_stats':
// TODO: Afficher les statistiques du client
break;
}
}
?>Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses et objetsLe mot-clé $thisMéthodesPropriétésConstructeur (__construct)Destructeur (__destruct)Récapitulatif - Calculatrice simple4Héritage
Héritage de baseLe mot-clé parent::Redéfinition des méthodesLe mot-clé finalClasses abstraitesRécapitulatif – Hiérarchie des employés7Encapsulation
Public, Protected, PrivateModificateurs d’accès en profondeurAccesseurs et mutateursDissimulation de l’informationPromotion des constructeurs (8.0)Récapitulatif – Système de fiches étudiant10Concepts avancés de la POO
Composition ou héritageInjection de dépendancesClasses anonymesÉnumérations (PHP 8.1)Fibres (PHP 8.1)Approfondissement du clonage d’objetsGénérateurs et itérateurs13Patrons de conception – Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode modèlePatron ÉtatPatron CompositePatron Dépôt2Espaces de noms et chargement automatique
Introduction aux espaces de nomsLe mot-clé useNorme de chargement automatique PSR-4Autoloader de ComposerRécapitulatif - Projet organisé5Interfaces et contrats
Introduction aux interfacesImplémentation des interfacesImplémentation de plusieurs interfacesInterface ou classe abstraiteIndication de type avec les interfacesRécapitulatif - Calculateur de formes8Méthodes magiques
Introduction aux méthodes magiques__toString et __debugInfo__get, __set, __isset, __unset__call et __callStatic__clone et clonage d’objets__serialize et __unserializeRécapitulatif - Collection personnalisée3Propriétés de classe
Propriétés d’instance vs statiquesConstantes dans les classesMéthodes et propriétés statiquesPropriétés privées et protégéesPropriétés en lecture seule (PHP 8.1)Récapitulatif - Gestionnaire de comptes bancaires6Polymorphisme
Révision de la redéfinition des méthodesPolymorphisme via les interfacesAnnotations de type et types unionLiaison statique tardiveRécapitulatif - Processeur de paiements9Traits
Introduction aux traitsUtilisation de plusieurs traitsRésolution des conflits entre traitsMéthodes abstraites dans les traitsTraits par rapport à l’héritage12Patrons de conception – Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FactoryPatron ObserverPatron Strategy15Défis finaux
Plateforme d’apprentissage en ligneSystème bancaireDéveloppement de personnages de jeuService de location de véhiculesEntraînez-vous par vous-même : Compilateur PHP en ligne