Page 1 sur 2

Class PDO²

Posté : 10 mai 2008, 19:15
par katagoto
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:

Posté : 10 mai 2008, 20:39
par rami
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!");
        }
    }

}
?>

Posté : 10 mai 2008, 21:35
par orgerix
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.

Posté : 10 mai 2008, 23:17
par rami
Effectivement, je viens d'éditer ;)

Posté : 10 mai 2008, 23:40
par SpintroniK
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 ?

Posté : 11 mai 2008, 00:12
par zeus
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.

Posté : 11 mai 2008, 00:42
par rami
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

Posté : 11 mai 2008, 09:30
par katagoto
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

Posté : 11 mai 2008, 09:52
par zeus
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 :(

Posté : 11 mai 2008, 10:00
par katagoto
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

++

Posté : 11 mai 2008, 10:13
par Cyrano
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

Posté : 11 mai 2008, 10:27
par SpintroniK
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 :?:

Posté : 11 mai 2008, 12:08
par katagoto
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 ?!?

Posté : 11 mai 2008, 12:13
par Cyrano
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

Posté : 11 mai 2008, 13:20
par SpintroniK
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)