Class PDO²

Mammouth du PHP | 1668 Messages

10 mai 2008, 19:15

Bonsoir à toutes et tous,

Voilà, j'aimerais créer une classe qui complète PDO j'ai donc commencé comme ça :
<?php
class sql extends PDO {
	public $lien;
	public function __construct($url, $login, $password, $nom){
		try
		{
			$lien = parent::__construct('postgresql:host='.$url.';dbname='.$nom, $login, $mdp);
		}

		catch(Exception $e)
		{
			$_SESSION['erreur']=$e;
			header("Location:erreur_sql.php");
		}

	}
}
?>
Voilà en gros j'aimerais inclure la gestion d'erreur à PDO...
Seulement, y a a peut près 20 fonctions dans PDO, je vais pas toutes les faires, y a t il un moyen pour que ma classe s'utilise de manière transparente ???

D'avance merci de vos réponses :wink:
"À ceux qui poursuivent leurs rêves et se spécialisent dans l'impossible" Joseph Kong

10 ans de PHP, déjà.

"moi jtrouve que katagoto il déchire!" Nagol

Mammouth du PHP | 983 Messages

10 mai 2008, 20:39

L'héritage est à éviter dès que possible en conception objet. Je te propose d'encapsuler plutôt une instance de PDO et d'utiliser la surcharge de méthodes. Je n'ai pas testé le code, donc il est probable que tu aies quelques erreurs, mais le principe est censé fonctionner :
class sql {
    /**
     * L'instance de PDO
     *
     * @var PDO
     */
    public $lien;

    /**
     * Constructeur de sql
     *
     * Tente une connexion au serveur de BD
     *
     * @param string $url
     * @param string $login
     * @param string $password
     * @param string $nom
     */
    public function __construct($url, $login, $password, $nom){
        try
        {
            // tu ne devrais pas hard coder le DSN car ta classe ne peut pas
            //être utilisée avec MySQL par exemple
            $lien = new PDO('postgresql:host='.$url.';dbname='.$nom, $login, $mdp);
        }

        catch(Exception $e)
        {
            $_SESSION['erreur']=$e;
            header("Location:erreur_sql.php");
        }

    }

    /**
     * Surcharge des méthodes PDO
     *
     * @param string $m nom de la méthode
     * @param array $a arguments à passer à la méthode
     * @throws BadMethodCallException si la méthode $m n'existe pas
     */
    public function __call($m, $a)
    {
        if( method_exists($lien, $m) )
        {
            //soit tu catch les exceptions ici, soit tu décides de les faire 
            //remonter au niveau supérieur
            try
            {
                $lien->$m();
            }
            catch (PDOException $e)
            {
                //gérer l'exception!
            }
        }
        else
        {
            throw new BadMethodCallException("La méthode PDO->$m() n'existe pas!");
        }
    }

}
?>
Modifié en dernier par rami le 10 mai 2008, 23:16, modifié 1 fois.

Mammouth du PHP | 693 Messages

10 mai 2008, 21:35

Juste comme ca, il y a un truc qui me choque, bien que je n'y connaisse pas grand chose en POO
$lien = parent::__construct
parent ne fait pas justement référence à la classe dont hérite la classe en cours ? Or la, la classe sql n'hérite de personne.. J'avoue que je ne vois pas comment ca pourrait marcher.

Mammouth du PHP | 983 Messages

10 mai 2008, 23:17

Effectivement, je viens d'éditer ;)

Eléphant du PHP | 209 Messages

10 mai 2008, 23:40

L'héritage est à éviter dès que possible en conception objet. Je te propose d'encapsuler plutôt une instance de PDO et d'utiliser la surcharge de méthodes.
Mon niveau en POO est plutôt faible, pourrais-tu expliquer pourquoi l'héritage est à éviter ?

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

11 mai 2008, 00:12

Je sens un débat intéressant. ;)

Pour moi, l'héritage, c'est pour spécialiser le fonctionnement d'une classe.
Ce que cherche à faire SpintroniK, à savoir reprendre le fonctionnement de la classe PDO en y ajoutant le traitement d'erreur est, pour moi, une spécialisation. Dans ce cas, l'héritage est une bonne solution.

Mais, dans tout les cas, la méthode magique __call() est une bonne solution pour la question de base.
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Mammouth du PHP | 983 Messages

11 mai 2008, 00:42

L'héritage casse le principe d'encapsulation. Une sous classe dépend du fonctionnement de la classe mère (en l'occurrence la classe PDO ici). Il faut au maximum éviter la dépendance à l'implémentation et travailler sur le concept de contrat (programmer par interface).

L'héritage peut fragiliser le code car il dépend de détails d'implémentation. Clairement, n'ayant pas la main sur l'implémentation de la classe PDO, utiliser la composition permet de s'affranchir du fonctionnement interne de la classe.

J'ai tendance à utiliser l'héritage dans du code que je maîtrise. C'est fort pratique pour factoriser du code. Mais dès que je dépend du code d'autrui, j'utilise au maximum la composition afin de rester insensible aux modifications futures de la librairie que j'utilise

Exemple :
Imagine que tu surcharge la méthode fetch de PDO pour ajouter un comportement particulier. Pour diverses raisons, les programmeurs de PHP décident de rendre la méthode finale dans la prochaine version de PDO (je sais, ce n'est pas possible en PHP, c'est simplement une illustration). Et là c'est le drame car ta classe ne fonctionnera plus.
Au contraire, si tu utilises la composition, ca sera complètement transparent dans ton code

Liens utiles:
http://www.artima.com/designtechniques/compoinh.html (à lire absolument)
http://blog.emmanueldeloget.com/index.p ... omposition

Je te conseille aussi le très bon livre : Java efficace de Joshua Bloch

Mammouth du PHP | 1668 Messages

11 mai 2008, 09:30

Je sens un débat intéressant. ;)
Erf
// tu ne devrais pas hard coder le DSN car ta classe ne peut pas
//être utilisée avec MySQL par exemple
Je tiens compte de ta remarque, mais je penses que tout le monde connait mes convictions su ce sujet et à défaut d'avoir raison, c'est toujours mon code...

Bref pour ceux qui ne l'aurait pas compris, j'essai d'éviter de surcharger mon code en local car je travail avec des codeurs pas très portés sur la sécurité, voilà...

Ensuite, merci à zeus, mais comment dois-je l'utiliser, j'ai bien une idée :
<?php
class sql {
   public function __call($methode, $parametres) {
         try
         {
            return $methode->$parametres;
         }
         catch(Exception $e) 
        { 
            $_SESSION['erreur']=$e; 
            header("Location:erreur_sql.php"); 
        } 
   }
}
Je crois que c'est ça

PS : Faites le débat après la résolution de mon problème SVP :roll:

PPS : J'ai fait du C++ (qui est connu pour sa méthode objet), et j'ai toujours été partagé entre le fait d'éliminer la redondance de mes applications quit à augmenter les dépendances, et j'en suis venu à la conclusion que moins il y aurait de dépendance plus les maintenances et les améliorations seraient simple... voilà pour moi
"À ceux qui poursuivent leurs rêves et se spécialisent dans l'impossible" Joseph Kong

10 ans de PHP, déjà.

"moi jtrouve que katagoto il déchire!" Nagol

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

11 mai 2008, 09:52

Ensuite, merci à zeus, mais comment dois-je l'utiliser, j'ai bien une idée :
public function __call($methode, $parametres)
C'est presque ça, ce code est fonctionnel sauf que c'est
public function __call($lien, $methode)
L'héritage casse le principe d'encapsulation. Une sous classe dépend du fonctionnement de la classe mère (en l'occurrence la classe PDO ici). Il faut au maximum éviter la dépendance à l'implémentation et travailler sur le concept de contrat (programmer par interface).

L'héritage peut fragiliser le code car il dépend de détails d'implémentation. Clairement, n'ayant pas la main sur l'implémentation de la classe PDO, utiliser la composition permet de s'affranchir du fonctionnement interne de la classe.

J'ai tendance à utiliser l'héritage dans du code que je maîtrise. C'est fort pratique pour factoriser du code. Mais dès que je dépend du code d'autrui, j'utilise au maximum la composition afin de rester insensible aux modifications futures de la librairie que j'utilise
Je comprend ces arguments là et je trouve qu'ils peuvent avoir un fond très judicieux.
Or, je pense qu'une bonne modélisation prend en compte l'état des objets avant même de penser au code.
Or, pour moi, une pomme est un fruit, et il y a héritage. Lorsque j'arrive au niveau de l'implémentation, il est trop tard pour refaire ce choix là.
Je suis surement un peu trop utopique, mais jusque là, prendre du temps sur une grosse conception ne m'a jamais causé de soucis irrémédiables.

PS : désolé katagoto :(
Modifié en dernier par zeus le 11 mai 2008, 10:00, modifié 1 fois.
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Mammouth du PHP | 1668 Messages

11 mai 2008, 10:00

Le sujet est résolut, je ne saisit juste pas nuance, mais je pense que ça vient du fait que $methode n'a pas été déclarer...

Merci à tous

++
"À ceux qui poursuivent leurs rêves et se spécialisent dans l'impossible" Joseph Kong

10 ans de PHP, déjà.

"moi jtrouve que katagoto il déchire!" Nagol

Mammouth du PHP | 19672 Messages

11 mai 2008, 10:13

L'héritage casse le principe d'encapsulation. Une sous classe dépend du fonctionnement de la classe mère (en l'occurrence la classe PDO ici). Il faut au maximum éviter la dépendance à l'implémentation et travailler sur le concept de contrat (programmer par interface).
Sur un plan purement logique, un point m'échappe dans ce raisonnement.

Je pars du principe de base que les fonctions natives d'une version stable d'un langage n'évolueront à priori pas de façon régressives, l'extension ne posera pas de problème dans le temps. Mais comme tu l'as souligné, si on suppose que l'évolution du langage déclare la classe PDO final et donc non extensible, tu n'auras pas le choix de faire une composition. En revanche, pour une modification dans son fonctionnement, que ce soit par héritage ou composition, tu vas quand même te heurter à un problème. L'objet instancié n'aura pas le même comportement et du coup son utilisation dans ta propre classe, qu'elle étende PDO ou en utilise une instance de composition, en sera modifiée également parce que le comportement des méthodes ou des propriétés en aura été modifié... Le résultat de ta propre classe sera donc obligatoirement différent aussi, non ?

Notez que je ne suis pas un gourou de la POO loin s'en faut, je pars peut-être d'une erreur d'interprétation :-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Eléphant du PHP | 209 Messages

11 mai 2008, 10:27

Je suis un peu d'accord avec le raisonnement de Cyrano, mais mon niveau en POO n'est pas excellent donc je peux me tromper.
En gros, si tu utilise PDO d'une façon ou d'une autre si une méthode de PDO est modifiée ça va forcément se répercuter sur ton code, quelque soit la technique que tu utilises pour appeler PDO, ça me parait plutôt logique...
Pour reprendre zeus, si un jour tous les fruits doivent être rouges (exemple très con) alors ta pomme deviendra forcément rouge.
Enfin si on réfléchit comme ça, ça paraît logique, maintenant peut être que ça n'est pas la bonne interprétation :?:

Mammouth du PHP | 1668 Messages

11 mai 2008, 12:08

Je me trompe sûrement (car moi non plus mon niveau de POO n'est pas "sublime"), mais en ajoutant un "calque" comme ça, si PDO change je n'aurais qu'à modifier ma classe et non tout mon code, ce sera plus rapide il me semble. Non ?!?
"À ceux qui poursuivent leurs rêves et se spécialisent dans l'impossible" Joseph Kong

10 ans de PHP, déjà.

"moi jtrouve que katagoto il déchire!" Nagol

Mammouth du PHP | 19672 Messages

11 mai 2008, 12:13

Je me trompe sûrement (car moi non plus mon niveau de POO n'est pas "sublime"), mais en ajoutant un "calque" comme ça, si PDO change je n'aurais qu'à modifier ma classe et non tout mon code, ce sera plus rapide il me semble. Non ?!?
Tout aussi logique, et même dans ce cas préférer la composition à l'héritage ne se justifie pas davantage...

C'est pour ça que j'attends avec intérêt un éclaircissement de rami sur ce point :-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Eléphant du PHP | 209 Messages

11 mai 2008, 13:20

Comment fait-on avec cette technique pour utiliser la méthode query de PDO?

j'ai essayé ceci : (dans la calsse) :
	public function query($mysql)
	{
		return($lien->query($mysql));
	}
et dans le script :
 $sql = new SQL($url, $login, $pass, $bdd);
$sql->query(...);...
mais j'ai un message d'erreur : Call to a member function query() on a non-object
Je comprends pas trop (et je suis mauvais :D)