PHP, POO et bases de donnees

Voilà, je suis sur un nouveau projet de site web.
C’est un projet par un étudiant pour des étudiants et je fais donc grosso modo ce que je veux.

Autrement dit, je veux en profiter pour en apprendre un maximum.
Je me suis donc imposé les choix suivants :

  • PHP5 avec un maximum de programmation orientée objet.
  • facilement skinnable et facilement traduisible dans une autre langue => UTF8, XML pour les textes intégrés, rien en hard et XSLT pour les templates

Pour le deuxieme point je me débrouille pas mal, ca ira sans probleme mais la POO me pose problème.

En fait ce n’est pas la poo qui pose problème mais l’utilisation de la base de donnée dans celle-ci. Je m’explique …

Prenons l’exemple d’un forum, lorsqu’on charge une page de topic et que l’on utilise la poo : on génère :

  • un objet topic. (le topic sur lequel on navigue)
  • un objet post par post affiché sur la page.
  • un objet user par post (l’auteur du post affiché).

Dans un cas idéal, on crée des constructeurs qui prennent en paramètre la clé primaire d’un enregistrement en db et on construit l’objet avec, on encapsule donc les requêtes liées à l’objet dans l’objet même. Le problème ici c’est que si on fait ca, on a une requête par constructeur appelé (soit bcp ici :stuck_out_tongue: ). Alors qu’en une requête avec des jointures cela suffisait. Si on fait cette requête hors des constructeurs on doit donc recuperer les resultats et construire l’objet avec … en quelque sorte, je trouve qu’on brise l’encapsulation.

au lieu de :

$topic = new topic($topic_id); // une requete $posts = $topic->Getposts($from, $nbr); // $nbr * 2 requetes (une pour le post, une pour l'auteur) for each ($posts as $post) $post->display();

on va avoir :

$mysqli->prepare ('SELECT blablabla FROM bla INNERJOIN ghghjgjhg INNERJOIN WHERE hjjhkjhk;'); $mysqli->bind_param (un tas de params); $mysqli->execute(); $mysqli->bind_result (un tas de resultats); while (mysqli->fetch()) {  $post = new post (le meme tas de resultats);  $post->display(); }

je trouve que la deuxième version n’apporte rien d’intéressant … c’est pas ca de la belle poo … mais je ne sais pas comment gérer pour que tout soit efficace et limiter les accès à la base. Je vais tester pour voir si les requetes preparees peuvent combler en partie les pertes de performances dues à un grand nombre de requetes mais ca m’etonnerait.

Je voudrais donc profiter de vos experiences, php ou asp de toute facon la problématique est la même.

Merci (en espérant que j’aie des réponses :stuck_out_tongue: )

[quote name=‹ Asarnil › date=’ 29 Jun 2005, 19:27’]Prenons l’exemple d’un forum, lorsqu’on charge une page de topic et que l’on utilise la poo : on génère :

  • un objet topic. (le topic sur lequel on navigue)
  • un objet post par post affiché sur la page.
  • un objet user par post (l’auteur du post affiché).

Dans un cas idéal, on crée des constructeurs qui prennent en paramètre la clé primaire d’un enregistrement en db et on construit l’objet avec, on encapsule donc les requêtes liées à l’objet dans l’objet même. Le problème ici c’est que si on fait ca, on a une requête par constructeur appelé (soit bcp ici  :stuck_out_tongue: ). Alors qu’en une requête avec des jointures cela suffisait. Si on fait cette requête hors des constructeurs on doit donc recuperer les resultats et construire l’objet avec … en quelque sorte, je trouve qu’on brise l’encapsulation.[/quote]
C’est très simple : l’objet topic possédera des objets post (qui contiendront des objets user).
De plus, AUCUNES requêtes SQL ne sera insérées directement dans le code de l’objet lui même.
En faisant ça, pas de problèmes.

Tes requêtes tu les fera faire part un autre type d’objets qui contiendront que les requêtes SQL.
Enfin, tu fais un objet forum, qui créera un objet topic, des objets post et user (à l’aide des objets précédents) :

class Forum {    public function show($id)    {        $result = $objetQuiContientLesRequetesDeForum()->getForumData($id);                    // Bon les noms sont à coucher dehors mais je suis en manque d'inspiration là ..                $topic = new Topic();        $topic->setTitle($result->get('title'));        $topic->setDate($result->get('date'));        ...        while($hasPost)        {            $post = new Post();            $post->setTitle(...);            ...            $topic->addPost($post);        }    } }
Le principe est là.

Bon après c’est mon point de vue. Il y en a d’autres.
En tout cas, je n’ai pas plus de requêtes qu’en « mode procédural », et je m’y retrouve parfaitement dans mon code.

Voila.
Bon courage.

donc mettre les requetes en dehors de l’objet (pour ce qui est d’objets qui possedent d’autre objets etc, je faisais déjà comme cà :stuck_out_tongue: la poo ca va, ce qui me derange c’est justement dacceder par exemple aux tables sql de la classe user hors de la classe user).

j’ai pense a un moment faire un fichier XML qui contiendrait toutes les requetes necessaires au site histoire de centraliser, je ne sais pas si c’est une bonne idée.

edit : non c’est pas une bonne idée, je vais faire comme tu dis.

et merci :stuck_out_tongue:

Ben moi ça ne me gène pas du tout.
Comme son nom l’indique, la base de données est là pour stocker les données, peu importe le fonctionnement du code qui vient ensuite. Avoir un objet par table, c’est bien. Mais ce n’est pas pour ça que les autres tables / objets n’ont pas le « droit » de manipuler cette table !

Personnellement je n’en ai pas besoin, car ça ne me sert pas, et ce n’est pas plus pratique (toujours pour moi).
Si toi ça peut te servir, et bien pourquoi pas. Mais si ça n’apporte rien, autant ne pas le faire. :stuck_out_tongue:

Je reponds a cote parce que j’y connais queudalle en POO et j’aime pas ca.

Non, c’etait pour ton desir de faire du multilangue. C’est top. Et crois moi, j’ai teste plein de systeme: Base de donnees (lent et illisible), XML (rapide mais illisible).
La vrai methode, certes parfois megachiante a configurer, c’est gettext.

LoneWolf
gettext rulez, et existe pour la quasi totalite des langage…

[quote name=‹ LoneWolf › date=’ 29 Jun 2005, 22:11’]Je reponds a cote parce que j’y connais queudalle en POO et j’aime pas ca.

Non, c’etait pour ton desir de faire du multilangue. C’est top. Et crois moi, j’ai teste plein de systeme: Base de donnees (lent et illisible), XML (rapide mais illisible).
La vrai methode, certes parfois megachiante a configurer, c’est gettext.

LoneWolf
gettext rulez, et existe pour la quasi totalite des langage…
[right][post=« 373017 »]<{POST_SNAPBACK}>[/post][/right][/quote]

Je regarderais mais plus pour ma culture générale que pour l’utiliser. J’aime XML parce qu’en plus de simplement mettre du texte, on peut créer des balises contenant :

  • le texte (forcément :P)
  • une description
  • l’url d’un screenshot démonstratif

sur base de ca, on peut faire une page de traduction relativement efficace.
et je trouve la méthode lisible si les balises sont bien choisies (on verra si je suis tjs du même avis au bout d’un beau gros fichier :P)

ai-je mentionné que j’aime le XML ? :stuck_out_tongue:

Gettext est une horreur. J’ai utilisé, et je n’utiliserai plus jamais en php. Suffit de tomber sur un serveur Windows (le support gettext chie mechamment sous windows) ou un serveur *nix ou l’admin n’a pas installe toutes les locales et ca ne marche pas. C’est juste trop reloud.

Salut,

Comme unreal je n’aime pas du tout gettext.

Pour la gestion des langues j’utilise un fichier XML par page du site.
Pour la structure je garde celle des fichiers properties (« version XML ») en Java : ça permet de garder facilement les fichier d’un langage à l’autre …
Ce qui donne quelque chose comme ça :

<properties> &nbsp; &nbsp;<entry key="page.title">Titre de la page</entry> &nbsp; &nbsp;<entry key="page.desc">Description de la page</entry> &nbsp; &nbsp;... </properties>

Ensuite vu que c’est lent à parser, on fait un cache, et ça roule bien.
Pour que ça soit pratique, on fait une petite classe « Lang » qui s’occupera de tout ça.
Pu cas faire un « echo Lang::get(‹ page.title ›); » par exemple :stuck_out_tongue:

C’est la méthode que j’utilise, et je la trouve pratique.

Bon ca derive parce que on parlait de POO mais j’ai deja essaye le XML en localisation. C’est juste injouable quand le projet devient trop gros.

Imaginez un texte comme ca a mettre sur une page web:

je mets quoi comme ID XML?

echo readxml("start.explanation.1",$lang)

Croyez moi, ca devient tres tres vite illisible, des qu’on a de plus en plus de texte partout. Parce que pour aller plus vite, ca devient vite « texte42 » et la… haha on se marre pour retrouver « putain mais c’est quoi ce texte la deja? »

Maintenant, je suis super d’accord que gettext est souvent chiant a configurer, mais a l’utilisation (ie programmation), c’est ce qui se fait de mieux.

LoneWolf
Apres, vous faites ce que vous voulez :stuck_out_tongue:

Je n’ai jamais eu ce problème.
Je dispose d’un éditeur avec une fonction recherche. Comme tout le monde ici je pense.
Donc pour retrouver un texte, c’est très rapide.

Je voudrais aussi rajouter quelque chose.
Stocker les données du fichier XML dans un tableau, c’est mieux en utilisant serialize qu’en fesant un fichier où on déclare ce tableau :

[code]// Au lieu de faire :
$lang = array();
$lang[‘key1’] = ‘…’;
$lang[‘key2’] = ‘…’;
$lang[‘key3’] = ‘…’;

Faire :
résultat de serialize($lang);[/code]
C’est plus rapide (testé et approuvé).

Bref, j’ai utilisé cette façon de faire déjà, et je n’ai pas eu de problèmes (que ça soit de lisibilité ou autre). C’est comme pour beaucoup de choses, il suffit de bien s’organiser au départ.

[quote name=‹ nic58 › date=’ 30 Jun 2005, 08:33’]Je n’ai jamais eu ce problème.
Je dispose d’un éditeur avec une fonction recherche. Comme tout le monde ici je pense.
Donc pour retrouver un texte, c’est très rapide.[/quote]
haha comment il me prend pour un imbecile lui.

Attend d’avoir des pages avec 20 ou 30 lignes de texte, de voir des code zarbi partout « texte42 », d’etre oblige de retourner sur le fichier XML « ah oui, ca veut dire ca » et de tomber sur « texte78 », de reeeetourner sur le fichier XML… enfin tu vois le concept.
J’ai fait ca pendant plus d’un an dans un projet « pro » (ie vendu a des clients… HAHA), ben… plus jamais. Vraiment hein. Meme les emmerdements d’install valent pas la galere incomensurable a relire un code plein de « texte* » qui n’a aucun sens sans le fichier xml a cote qu’il faut chercher et chercher…

LoneWolf
Tu comprendras quand tu utilisera ca dans un gros truc :stuck_out_tongue:

Je ne sais pas qui prend l’autre pour un imbécile, mais je ne suis pas sur que ça soit moi …
Si tu prends tout de travers, moi j’y peux rien. Décontractes un peu tu veux ?
Enfin bref.

C’est le cas : je n’ai pas eu de problèmes.

Sur ce, tu as ta façon, j’ai la mienne.
Tu y arrives avec la tienne, moi avec la mienne, et bien tant mieux.
Je propose ma façon de faire, ni plus ni moins. Si t’es pas content, c’est ton problème : je ne te demande pas de commentaires, sauf les constructifs. Les choses du genre « blabla c’est nul, tais toi ça marche pas ton truc » tu te les gardes.

Ah et tu pourras toujours faire ton « pro » avec moi et essayer de me prendre de haut comme tu viens de le faire, ça marchera pas hein.
Ce n’est pas parce que TU n’y arrives pas que c’est INJOUABLE pour tout le monde, j’espère que c’est clair. Question de bon sens.

Oula attend, y a jamais eu de notion « prendre de haut », ou alors je me suis mal exprime.
Les signatures en dessous de mon nom, c’est pour deconner, et je mets en general un smiley specifique.

Maintenant, je m’etonne que tu puisses gerer ca avec un gros site, ayant deja eu a gerer un truc comme ca (bon, c’etait peut etre pas tout a fait pareil, mais c’etait bien injouable).
Je n’ai aucune notion de ton experience en dev, et j’essaye de donner un apercu de la mienne, mais il n’y avais pas d’intention « de me la peter avec mes sites pro » (a noter que je me suis barre de la societe, donc ahem - mais ca, tu le savais pas)

L’utilisation de gettext est un conseil, c’est la meilleure methode que je connaisse actuellement, meme si Gloppy me signale mieux sur .net, bah ok hein :stuck_out_tongue:
Et puis bon, le coup du « moteur de recherche dans un editeur », c’est bas. Donc je me suis peut etre un peu emporte a l’insu de mon plein gre ™Virenque :stuck_out_tongue:

Bref, desole pour la derive, mea culpa et tout, je la ferais plus :stuck_out_tongue:

LoneWolf
Quand je gueule vraiment, c’est plus virulent (rime) :stuck_out_tongue:

Ok pas de problèmes.
Désolé. :stuck_out_tongue:

Je serais ravi d’en discuter si tu veux, mais peut être sur un autre sujet topic.
Car enfaite je ne comprends pas pourquoi tu ne t’y retrouves pas, car une fois la page bien « découpée », ça reste clair, et les fichiers ne sont pas énormes.

Le xml, ou tout autre solution que gettext, c’est peut être très bien.
Mais quid de la gestion des pluriels (dont la gestion peut être différente suivant la langue), de l’encodage et autres joyeuseté ?
Gettext est peut être très lourd, mais ca il sait bien faire…
Alors, pourquoi réinventer la roue en xml ?

Par contre, l’extension de gettext en php fait appel à des variables d’environnement et c’est extrémement con. Car suivant l’os et la manière dont est installé php, module ou cgi, si deux utilisateurs font deux requêtes simultanées, un anglais et un allemand, et que l’allemand est le dernier à fixer les variables d’env, l’anglais va se retrouver avec gutentag au lieu de hello !

Concernant la POO, j’ai un peu le même dilemme, mais je n’ai jamais trouver de solution réellement satisfaisante.

Attaquer X tables voir même X tables dans X bases n’est pas en soit un problème au niveau objet (c’est l’objet qui récupère lui même ses données, donc l’encapsulation est respectée).

Par contre, si une base, une table ou un champ est modifiée, bonjour la galère pour répercuter dans tous les objets.

Ok, un bon programmeur est censé avoir fait une analyse de son bignou avant, mais dans la pratique, ce genre de chose arrive.

Dans un petit projet, ca va encore. Dans un moyen ou un gros, ca peut être galère.

Mais encore une fois, j’ai pas vraiment de solution.

Peut être en passant par des procédures stockées au niveau du sgbd appelé par les objets… mais cette solution (outre le fait que je ne sais pas si c’est jouable) exclue mysql…

A+

Pour ce qui est de l’encodage, avec XML, tu mets tout en UTF-8 : ton xml, ta db, ta sortie, tout. Du coup, plus de problème de charset, le seul inconvénient c’est que php ne gère pas en natif l’utf8 (ca doit se régler pour la 5.1) tu dois donc utiliser l’extension mb_strings.

edit : je supprime p-mon passage sur les procedures stockee de mysql, c’est pour la v5 :stuck_out_tongue:

Mysql 4.1 ne supporte pas les procédures stockées.
Uniquement la 5.x, encore en béta.
Après, certainement que l’api PHP est préte pour les supporter.

Si tu fait une procédure qui execute ta requete en jointure, tu n’as plus de problème.
Et si la structure de tes bases change, tu n’as que la procédure à modifier.
Autre avantage, si ta base est attaquée par autre chose que php, l’attaquant dispose de la même « API » que toi.
En faisant cela, les objets PHP ne servent plus que de « wrapper » avec la logique de l’application/site.
Je trouve cela bien plus propre et ca facilite grandement l’interopérabilité et la maintenance.
En plus, la logique relationnelle reste au niveau de la base, et l’objet au niveau de php.

[quote name=‹ Asarnil › date=’ 30 Jun 2005, 12:44’]Pour ce qui est de l’encodage, avec XML, tu mets tout en UTF-8 : ton xml, ta db, ta sortie, tout. Du coup, plus de problème de charset, le seul inconvénient c’est que php ne gère pas en natif l’utf8 (ca doit se régler pour la 5.1) tu dois donc utiliser l’extension mb_strings.
[right][post=« 373212 »]<{POST_SNAPBACK}>[/post][/right][/quote]

Mouais, un peu sauvage comme méthode, de stocker X octets là ou 1 seul suffit.
Je sais bien que la ressource matériel n’est plus un problème, m’enfin…
Sans compter le surcout de mettre du mb_string partout et surtout de ne pas en oublier un appel qqpart.

Et ca ne régle pas la gestion des pluriels.

A+

PS : j’aimerai bien l’avis de Pèrecil (ou Lonewolf, je ne sais plus) pour le coup des procédures stockées, car le monsieur utilise postgesql qui doit permettre de faire ce genre de chose.

[quote name=‹ azazel › date=’ 30 Jun 2005, 12:53’]PS : j’aimerai bien l’avis de Pèrecil (ou Lonewolf, je ne sais plus) pour le coup des procédures stockées, car le monsieur utilise postgesql qui doit permettre de faire ce genre de chose.
[right][post=« 373216 »]<{POST_SNAPBACK}>[/post][/right][/quote]
Si je dis pas de conneries, les procedures stockes sont des series de commandes SQL regroupees dans une fonction (enfin c’est comme ca dans MSSQL).
Dans PGSQL, c’est la meme chose:
http://www.postgresql.org/docs/7.4/interactive/plpgsql.html
Sauf qu’on peut aussi utiliser d’autres langages:
http://www.postgresql.org/docs/7.4/interactive/xplang.html

Effectivement, tout ca n’existe pas dans MySQL

LoneWolf
PGSQL, ca rulez tout. :stuck_out_tongue:

Pour les procedures stockees, j’avais edite :stuck_out_tongue: (et si quelqu’un s’y connait, une intervention serait chouette, j’y connais pas grand chose :P)

Maintenant pour l’unicode, je pense que ce serait une bonne chose qu’il s’impose comme charset universel. A quoi bon s’embrouiller avec moult charsets alors qu’un suffit ? d’autant que comme tu le dis les ressources matérielles ne sont plus un problème. pour ce qui est des mb_string, c’est lourd oui, mais ca va changer.

Je rajoute une question à ma question initiale tiens.

préférez vous :

ou

$query = $mysqli->prepare('SELECT * FROM users WHERE id=?'); $query->bind_param('i', $id); $query->execute();

La première est plus performante, la deuxième me semble plus logique.
Dans le cas d’une requête unique (sinon la deuxième l’emporte d’office)