Bonjour,

Je débute le développement d'un petit site web et je me dis que j'allais utiliser quelques packages sympas disponibles avec Composer, le premier étant PHPAuth pour gérer mes identifications de personnes.
J'ai aussi fait un "multiton" me permettant d'avoir un accès à plusieurs BDD. C'était à l'origine pour un autre projet mais je me suis dis que j'allais m'en reservir ici tant qu'à faire.

Le code de ce multion:

<?php

namespace App;

use PDO;
use PDOException;
use Exception;

class Mpdo {

    /**
     * @var array
     */
    private static
        $instance = array(),
        $dbinfo = Array();

    /**
     * @var PDO
     */
    private
        $pdo;

    /**
     * Mpdo constructor.
     * @param $dbname
     */
    private function __construct($dbname) {
        try {
            $this->pdo = new PDO(self::$dbinfo[$dbname]['dsn'], self::$dbinfo[$dbname]['user'], self::$dbinfo[$dbname]['password']);
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch(PDOException $e) {
            echo 'Connexion échouée sur '.$dbname.' : ' . $e->getMessage() ;
        }
    }

    /**
     * @param $method
     * @param $args
     * @return mixed
     */
    final public function __call($method, $args) {
        $result = call_user_func_array(array($this->pdo,$method) , $args);
        return $result;
    }

    /**
     *
     */
    public function __clone() {
        // Désactivation du clônage
    }

    /**
     * @param $dbname
     * @return mixed
     * @throws Exception
     */
    public static function getInstance($dbname) {

        require_once(dirname(__FILE__)."/define.const.php");

        if(empty(self::$dbinfo)) {
            self::$dbinfo = $db;
        }

        if(!array_key_exists($dbname,self::$dbinfo)) {
            throw new Exception('La base de donnée "'.$dbname.'" n\'est pas configurée!');
        }

        if(!array_key_exists($dbname, self::$instance)) {
            self::$instance[$dbname] = new Mpdo($dbname);
        }

        return self::$instance[$dbname];
    }
}

Dans mon fichier index.php, je fais ceci:

$cnx = Mpdo::getInstance('bdd');

$config = new PHPAuthConfig($cnx);
$auth = new PHPAuth($cnx, $config);

Problème, j'obtiens l'exception suivante:
Fatal error: Uncaught TypeError: Argument 1 passed to PHPAuth\Config::__construct() must be an instance of PDO, instance of App\Mpdo given,

Je comprends bien que je lui envoie une instance de Mpdo, mais le contenu de cette instance est identique à ce que je lui donnerait avec un $cnx = new PDO(...).
De fait, le constructeur de Config demande bien comme premier paramètre "\PDO $dbh".

Ma question est donc la suivante: comment puis-je faire pour pouvoir gérer la connexion à la BDD avec mon multiton pour mes class à moi et PHPAuth (et sans doute d'autres plus tard), je ne parviens pas à trouver de solution, et je me dis que le problème serait le même en utilisant un sigleton de toute façon car on ne renverrait pas une instance de PDO.

Par avance, merci pour votre aide, c'est peut-être tout bête mais je sèche...

3 réponses


quenti77
Réponse acceptée

Pour @lartak : Un multiton étant comme un singleton le fait de mettre le constructeur en privée est normal (c'est la base même du singleton ^^) : Singleton

Après pour @jouvrard : Je te conseil vivement d'éviter au maximum les singletons/multiton dans une application car cela génère une dépendance forte entre tes classes. Si un jour tu veux changer et passer par exemple de PDO à un nouveau truc qui serait mieux il faudrait changer beaucoup de code.

Le mieux est de faire de l'injection de dépendance : Tuto grafikart injection

Cela évite une dépendance forte et aussi te permettra plus tard de pouvoir facilement tester tes classes.

Voici par exemple :

Et avec ça et php-di (un container d'injection de dépendance) j'ai juste besoin de demander un objet qui implémente un IConnection (comme pour le fichier DbRepository) et il va me créer une instance de PDO/Connection si ce n'est pas fait ou utiliser celle déjà créé.

Voici la vidéo sur le DIC : Tuto grafikart DIC

Je préfère te le dire maintenant que tu arrive à un moment ou c'est galère comme j'ai pu l'avoir quand j'avais fais que des singleton/factory dans mon app et que je me retrouvais comme un con avec toutes mes dépendances bien relou ^^

Bonsoir.
Pour commencer, tu fais une grosse erreur.
La fonction __construct, doit toujours être en visibilité public, sinon tu ne peux logiquement pas y faire appel en dehors de celle-ci.
ensuite l'erreur est logique étant donné que tu veux définir l'instance avec le retour de ton constructeur, sauf que celui-ci ne retourne rien, du coup ton instance n'est pas une instance de PDO, mais de ta classe Mpdo.
D'ailleurs, comment veux tu pouvoir récupérer une instance de PDO, alors que le seul moment ou tu utilises PDO, c'est en définissant la propriété pdo, sauf que tu ne fais appel à aucun moment à celle-ci.

jouvrard
Auteur

@Lartak : Comme l'a donc dit quenti77, le fait que le constructeur soit privé est normal, mais merci d'avoir proposer quelque chose et d'avoir pris le temps d'y regarder! :)

@quenti77 : Moi qui pensais que le singleton était LA solution pour une connexion aux BDD efficace, je me rends compte que je n'ai plus qu'à tout repenser. :D
J'ai parcouru en diagonal tes exemples, il va falloir que je suive les tutos correspondants sur Grafikart car j'avoue avoir du mal à tout comprendre.

Merci beaucoup en tout cas!