PHP - une couche d'abstraction DB utiliser la classe statique vs objet singleton?

Je ne veux pas créer une discussion sur singleton mieux que statique ou mieux que global, etc. J'ai lu des douzaines de questions sur des sujets similaires sur SO, mais je n'ai pas pu trouver de réponse à cette question spécifique, donc j'espère que quelqu'un pourrait maintenant m'éclairer en répondant à cette question avec une (ou plusieurs) véritable EXEMPLES simples, et pas seulement des discussions théoriques.

Dans mon application j'ai l' classe DB typique pour abstraire la couche DB et pour effectuer des tâches sur DB sans avoir à écrire partout en code mysql_connect / mysql_select_db / mysql...

je pourrais écrire la classe comme une CLASSE STATIQUE:

class DB
{
   private static $connection = FALSE; //connection to be opened

   //DB connection values
   private static $server = NULL; private static $usr = NULL; private static $psw = NULL; private static $name = NULL;

   public static function init($db_server, $db_usr, $db_psw, $db_name)
   {
      //simply stores connections values, without opening connection
   }

   public static function query($query_string)
   {
      //performs query over alerady opened connection, if not open, it opens connection 1st
   }

   ...
}

OR as a SINGLETON:

class DBSingleton
{
   private $inst = NULL;
   private $connection = FALSE; //connection to be opened

   //DB connection values
   private $server = NULL; private $usr = NULL; private $psw = NULL; private $name = NULL;

   public static function getInstance($db_server, $db_usr, $db_psw, $db_name)
   {
      //simply stores connections values, without opening connection

      if($inst === NULL)
         $this->inst = new DBSingleton();
      return $this->inst;
   }
   private __construct()...

   public function query($query_string)
   {
      //performs query over already opened connection, if connection is not open, it opens connection 1st
   }

   ...
}

puis après dans mon application si je veux interroger le DB je pourrais faire

//Performing query using static DB object
DB:init(HOST, USR, PSW, DB_NAME);
DB::query("SELECT...");

//Performing query using DB singleton
$temp = DBSingleton::getInstance(HOST, USR, PSW, DB_NAME);
$temp->query("SELECT...");

pour moi Singleton a le seul avantage d'éviter de déclarer comme static chaque méthode de la classe. Je suis sûr que certains d'entre vous pourraient me donner un exemple de véritable avantage de singleton dans ce cas particulier. Merci à l'avance.

22
demandé sur Marco Demaio 2010-05-15 20:46:25

5 réponses

Quel est le problème avec le suivant exemple (simplifié):

class Database
{
    protected $_connection;

    protected $_config;

    public function __construct( array $config ) // or other means of passing config vars
    {
        $this->_config = $config;
    }

    public function query( $query )
    {
        // use lazy loading getter
        return $this->_getConnection()->query( $query );
    }

    protected function _getConnection()
    {
        // lazy load connection
        if( $this->_connection === null )
        {
            $dsn = /* create valid dsn string from $this->_config */;

            try
            {
                $this->_connection = new PDO( $dsn, $this->_config[ 'username' ], $this->_config[ 'password' ] );
            }
            catch( PDOException $e )
            {
                /* handle failed connecting */
            }
        }

        return $this->_connection;
    }
}

$db1 = new Database( array(
    'driver'   => 'mysql',
    'host'     => 'localhost',
    'dbname'   => 'test',
    'username' => 'test_root',
    'password' => '**********'
) );

$db2 = new Database( array(
    'driver'   => 'pgsql',
    'host'     => '213.222.1.43',
    'dbname'   => 'otherdb',
    'username' => 'otherdb_root',
    'password' => '**********'
) );

$someModel       = new SomeModel( $db1 );
$someOtherModel  = new SomeOtherModel( $db2 );
$yetAnotherModel = new YetAnotherModel( $db2 );

ceci montre comment vous pouvez utiliser des connexions de chargement paresseuses, et encore avoir la flexibilité d'utiliser des connexions de base de données différentes.

Les instances de la base de données ne se connectent à leur connexion individuelle que lorsqu'un objet qui consomme une des instances (dans ce cas un des modèles) décide d'appeler une méthode de l'instance.

7
répondu Decent Dabbler 2011-04-09 15:55:11

dans mon projet le plus récent, je suis allé en fait contre les "bons" principes de conception en faisant la classe de base de données entièrement statique. La raison derrière ceci est que j'ai utilisé beaucoup de cache sur les objets PHP. À l'origine, j'ai fait passer la base de données par le constructeur de chaque objet sous forme d'injection de dépendances, mais je voulais m'assurer que la base de données ne devait pas se connecter à moins d'une nécessité absolue. Ainsi, l'utilisation d'une base de données comme variable membre de cet objet n'aurait pas été pratique parce que si vous désérialisez un objet du cache, vous ne voudriez pas vous connecter à la base de données à moins que vous ayez réellement effectué une opération dessus.

donc à la fin je n'avais que deux fonctions statiques (publiques), Database::fetch() et Database::execute() qui vérifieraient si oui ou non il s'était déjà connecté, et si non, il se connecterait et exécuterait la requête. De cette façon, je n'aurais pas à m'inquiéter de la désérialisation et je me connecterais aussi rarement que possible. Techniquement ce qui rend le test de l'unité impossible.

vous n'avez pas toujours à suivre toutes les bonnes pratiques. Mais je recommanderais quand même de ne pas faire ce que j'ai fait puisque certains le considéreraient comme une optimisation prématurée.

4
répondu Lotus Notes 2010-05-15 19:41:45

mon conseil: arrêtez D'utiliser Singleton et static tous ensemble.

Pourquoi? Parce que vous insérerez des dépendances qui rendront votre code inutilisable dans d'autres projets, et ne permettrez pas de le tester à l'unité. Oubliez aussi le couplage lâche si vous utilisez singleton.

Les solutions de rechange? Injection De Dépendance. http://www.potstuck.com/2009/01/08/php-dependency-injection

3
répondu danidacar 2011-04-15 06:45:20

mise en DB bibliothèque statique est certainement plus courte et plus rapide, que de le faire:

$db = DBSingleton::blabla(); // everytime I need ya

mais aussi, puisqu'il est global, tentant à utiliser partout.

alors, choisissez d'autres méthodes si vous voulez code propre... et choisissez statique si vous besoin rapide de code ;-)

1
répondu Martin 2012-04-18 21:35:13
/* Data base*/
 class Database
{
    /* Database field definition */
    private static $_instance; /instance
    private $_connection;
    private $DB_USER = "database_user_name_here";
    private $DB_PASS = "your_password_here";
    private $DB_NAME = "your_database_name_here";
    private $DB_SERVER = "localhost";

    /* Initiate the database connection */
    private function __construct()
    {
        $this->_connection = new mysqli($this->DB_SERVER ,
                                        $this->DB_USER ,
                                        $this->DB_PASS ,
                                        $this->DB_NAME);
        /* Test if connection succeeded */
        if (mysqli_connect_errno()) {
            die("Database connection failed: " .
                mysqli_connect_error() .
                " (" . mysqli_connect_errno() . ")"
            );
        }
    }

    /**
     * Instance of the database
     * @return Database
     *
     */
    public static function Instance()
    {
        if (!self::$_instance) { // If no instance then make one
            self::$_instance = new self();
        }

        return self::$_instance;
    }

    /**
     * Void duplicate connection
     */
    private function __clone() { }

    /* Return a connection */
    public function getConnection()
    {
        return $this->_connection;
    }

}

/** This is how you would use it in a different class.
  @var TYPE_NAME $connection */
$db = Database::Instance();
$connection = $db->getConnection();
-1
répondu Taban Cosmos 2015-08-22 03:38:40