Forum Programmation.php J'ai besoin d'un avis extérieur pour m'aider...

Posté par . Licence CC by-sa
Tags : aucun
4
18
juil.
2016

Bonjour à tous,

Je suis encore en train de reprendre un code qui ne m'appartient pas, et je suis peut être (sans doute?) en train de faire de la merde…

Pour me débarrasser d'un fichier de fonctions énorme et impossible à maintenir sans efforts démentiels, j'ai chercher à rassembler dans des classes toutes les fonctions liées à un type de données. Par exemple, j'ai une classe "utilisateur" avec un nom, prenom, adresse, CP, ville.

Dans l'ancien code, lorsqu'on voulait tous les utilisateurs d'une ville données, une fonction faisait la requete SQL ("select * from utilisateurs where ville = 'paris'), et renvoyais directement le resultSet. Charge ensuite à la page PHP de traiter les enregistrements :

while($row = mysqli_fetch_array($result)) {
...
}
C'est clairement la manière de faire qui me semble être la plus optimale, sauf que j'aimerais vraiment (mais alors vraiment) séparer l'interface avec les traitements issus de la base de données.

j'ai donc créé une fonction statique qui renvoie un tableau d'objet "utilisateur". Ca fonctionne, ça à l'air pas mal, sauf qu'au niveau performances, c'est juste pas possible !!! En gros, je fais une première requête pour récupérer les identifiants des utilisateurs concernés (select id from utilisateurs where ville = 'paris'), et ensuite, je crée une instance (utilisateur = new utilisateur(id) ) pour chaque utilisateur que je stocke dans un tableau, qui est finalement retourné par la fonction. Sauf que forcément, chaque appel à "new utilisateur(id)" me refait une requête SQL…

Si fonctionnellement, je trouve ça plus élégant, au niveau performance, je transforme quelque chose qui fait une seule requête et qui traite ligne par ligne, par quelque chose qui fait n+1 requêtes (suivant le nombre d’utilisateurs), qui fait une première boucle pour stocker ça dans un tableau, et qui fait encore une deuxième boucle pour faire l'affichage ! Sur-consommation de mémoire et de temps CPU !

Et toi cher journal, comment me conseilles tu de régler le problème ?
```

  • # Proxy de données

    Posté par (page perso) . Évalué à 5.

    Le cadriciel Symfony utilise la notion de proxy de données pour éviter cette cascade qui fait chuter les performances. L'idée est qu'on n'instancie l'objet que quand on y touche réellement.

    Donc tu instancies seulement des proxys d'utilisateur, qui eux ne font pas de requete SQL…

    ⚓ À g'Auch TOUTE! http://afdgauch.online.fr

    • [^] # Re: Proxy de données

      Posté par . Évalué à 1.

      J'avoue, je ne comprends qu'à moitié la réponse… Si on instancie quand on y touche, alors ça arrive dès qu'on veut l'afficher, non ?

      Ce que je comprends en revanche, c'est que j'ai déjà du mal à faire des modifications dans le code sans trop foutre en l'air l'existant, alors de là à utiliser un nouveau framework, je crois que c'est pas pour tout de suite !

      Je vais quand même regarder cette notion de "proxy", on ne sait jamais, ca pourrait me donner des idées.

      merci !

  • # Une classe "ensemble d'utilisateur"

    Posté par . Évalué à 2.

    Moi pour commencer, je ferai une classe utilisateur et une classe "ensemble d'utilisateur" qui serait une liste ou un ensemble d'instance d'utilisateur. Cette classe aurait une méthode (surement un constructeur même) qui permettrait de générer la liste et d'instancier tous les utilisateurs à partir d'un critère de recherche/une requête SQL et donc en ne faisant qu'une requête.

  • # constructeur privé et méthodes statiques

    Posté par (page perso) . Évalué à 3.

    Voici comment j'ai l'habitude de gérer la création d'objets au niveau d'une couche métier

    1) le constructeur est privé ;
    2) le constructeur prend en paramètre les données brutes issues d'une requête ;
    3) toute instanciation passe par une méthode static : que ce soit pour la création d'un nouvel objet métier (création d'un utilisateur) ou la récupération d'un objet métier existant (utilisateur). Les méthodes static renvoie un objet (getUserByID) ou une collection d'objets (getUsersByVille) en fonction des besoins. L'avantage de l'utilisation de méthode static pour l'instanciation des objets est de rajouter la sémantique d'une opération (avec un new, tu ne sais pas si tu créé un nouvel objet métier ou si tu récupères un objet déjà existant, tandis qu'avec un getUserByID par exemple, tu sais que tu récupères un utilisateur existant).

    Ensuite, pour la liste des utilisateurs par ville, tu fais une méthode statique qui :
    1) effectue une requête pour récupérer la liste des utilisateurs
    2) dans une boucle, effectue l'instanciation à proprement parler.

    Ainsi, tu ne fais plus qu'une seule requête.

    Par contre, tu auras toujours les deux boucles : une pour récupérer les données, et une pour les afficher. Mais ça, c'est parce que tu sépares vue et modèle (et d'un point de vue maintenance, c'est une bonne chose).

    • [^] # Re: constructeur privé et méthodes statiques

      Posté par . Évalué à 1.

      Merci pour ces conseils. J'en arrivais à peu prêt à la même conclusion : ma méthode getUserByVille est déjà statique, seulement, je ne voyais pas forcément comment créer mes objets derrière… Il va sans doute falloir que je créé un constructeur spécifique qui créé l'objet sans faire de requête, mais avec un tableau de données déjà prêt (mysqli_fetch_array par exemple).

      Merci pour toutes vos réponses.

  • # Paramêtre dans ta fonction de récupération

    Posté par . Évalué à 2. Dernière modification le 19/07/16 à 21:50.

    Un moyen simple serait d'ajouter un paramètre "préchargement" à ta fonction de récupération qui si il est passé à true va en plus de te renvoyer les ids de tes utilisateur effectuer la récupération des donnés et charger tes objets utilisateurs comme des singleton en mémoire.
    Cela peut aussi se faire avec une seconde méthode prenant une liste d'ids. Dans ce cas cela fera deux requêtes mais c'est déjà beaucoup mieux que une par utilisateur.
    Lors de l'instanciation ultérieure de tes objets il seront déjà chargés en mémoire avec leurs données.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.