Existe-t-il un cas d'utilisation pour les singletons avec accès à la base de données en PHP?

138

J'accède à ma base de données MySQL via PDO. Je configure l'accès à la base de données et ma première tentative a été d'utiliser les éléments suivants:

La première chose à laquelle j'ai pensé est global:

$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd');

function some_function() {
    global $db;
    $db->query('...');
}

Ceci est considéré comme une mauvaise pratique. Après une petite recherche, je me suis retrouvé avec le motif Singleton , qui

"s'applique aux situations dans lesquelles il doit y avoir une seule instance d'une classe."

Selon l'exemple du manuel, nous devrions faire ceci:

class Database {
    private static $instance, $db;

    private function __construct(){}

    static function singleton() {
        if(!isset(self::$instance))
            self::$instance = new __CLASS__;

        return self:$instance;
    }

    function get() {
        if(!isset(self::$db))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd')

        return self::$db;
    }
}

function some_function() {
    $db = Database::singleton();
    $db->get()->query('...');
}

some_function();

Pourquoi ai-je besoin de cette classe relativement nombreuse alors que je peux le faire?

class Database {
    private static $db;

    private function __construct(){}

    static function get() {
        if(!isset(self::$db))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd');

        return self::$db;
    }
}

function some_function() {
    Database::get()->query('...');
}

some_function();

Ce dernier fonctionne parfaitement et je n'ai plus à m'inquiéter $db.

Comment puis-je créer une classe de singleton plus petite, ou y a-t-il un cas d'utilisation pour les singletons qui me manque dans PHP?

seriousdev
la source
Il y a beaucoup de ressources et de discussions dans cette question connexe: «Qu'est-ce qui est si mauvais à propos des singletons?
FruitBreak

Réponses:

80

D'accord, je me suis posé la question pendant un moment quand j'ai commencé ma carrière. Je l'ai implémenté de différentes manières et j'ai trouvé deux raisons de choisir de ne pas utiliser de classes statiques, mais elles sont assez importantes.

La première est que vous trouverez très souvent quelque chose dont vous êtes absolument sûr de ne jamais avoir plus d'une instance, vous en avez finalement une seconde. Vous pouvez vous retrouver avec un deuxième moniteur, une deuxième base de données, un deuxième serveur - peu importe.

Lorsque cela se produit, si vous avez utilisé une classe statique, vous êtes dans un refactor bien pire que si vous aviez utilisé un singleton. Un singleton est un modèle douteux en soi, mais il se convertit assez facilement en un modèle d'usine intelligent - peut même être converti pour utiliser l'injection de dépendances sans trop de problèmes. Par exemple, si votre singleton est obtenu via getInstance (), vous pouvez facilement le changer en getInstance (databaseName) et autoriser plusieurs bases de données - aucun autre code ne change.

Le deuxième problème est le test (et honnêtement, c'est le même que le premier problème). Parfois, vous souhaitez remplacer votre base de données par une base de données fictive. En fait, il s'agit d'une seconde instance de l'objet de base de données. C'est beaucoup plus difficile à faire avec les classes statiques qu'avec un singleton, il suffit de simuler la méthode getInstance (), pas toutes les méthodes d'une classe statique (ce qui dans certains langages peut être très difficile).

Cela se résume vraiment aux habitudes - et quand les gens disent que les «globaux» sont mauvais, ils ont de très bonnes raisons de le dire, mais ce n'est pas toujours évident jusqu'à ce que vous ayez vous-même touché le problème.

La meilleure chose que vous puissiez faire est de demander (comme vous l'avez fait) puis de faire un choix et d'observer les ramifications de votre décision. Avoir les connaissances nécessaires pour interpréter l'évolution de votre code au fil du temps est beaucoup plus important que de le faire correctement en premier lieu.

Bill K
la source
15
Vous dites que les singletons se dégradent bien en DI, mais n'est-ce pas votre exemple de getInstance(databaseName)dispersion des références à un référentiel global d'instances dans tout votre code? Le code qui appellerait getInstancedevrait avoir la ou les instances injectées par le code client, et ne devrait donc pas avoir besoin d'appeler getInstanceen premier lieu.
Will Vousden le
1
@Will Vousden Correct, c'est une sorte de palliatif. Ce n'est pas vraiment DI, mais cela peut être assez proche. Par exemple, que se passe-t-il s'il s'agit de getInstance (supportedDatabase) et que l'instance renvoyée a été calculée en fonction de la base de données transmise? Le but est d'éviter d'effrayer les personnes avec un cadre DI jusqu'à ce qu'elles soient prêtes pour cela.
Bill K
320

Les singletons ont très peu - sinon dire non - d'utilisation en PHP.

Dans les langages où les objets vivent dans la mémoire partagée, les singletons peuvent être utilisés pour réduire l'utilisation de la mémoire. Au lieu de créer deux objets, vous référencez une instance existante à partir de la mémoire d'application partagée globalement. En PHP, une telle mémoire d'application n'existe pas. Un Singleton créé dans une requête vit exactement pour cette requête. Un singleton créé dans une autre requête effectuée en même temps est toujours une instance complètement différente. Ainsi, l'un des deux objectifs principaux d'un Singleton n'est pas applicable ici.

De plus, de nombreux objets qui ne peuvent exister conceptuellement qu'une seule fois dans votre application ne nécessitent pas nécessairement un mécanisme de langage pour appliquer cela. Si vous n'avez besoin que d'une seule instance, n'en instanciez pas une autre . Ce n'est que lorsque vous ne pouvez avoir aucune autre instance, par exemple lorsque les chatons meurent lorsque vous créez une seconde instance, que vous pouvez avoir un cas d'utilisation valide pour un singleton.

L'autre objectif serait d'avoir un point d'accès global à une instance au sein de la même requête. Bien que cela puisse sembler souhaitable, ce n'est vraiment pas le cas, car cela crée un couplage avec la portée globale (comme toutes les globales et les statiques). Cela rend les tests unitaires plus difficiles et votre application en général moins maintenable. Il existe des moyens d'atténuer cela, mais en général, si vous avez besoin d'avoir la même instance dans de nombreuses classes, utilisez l' injection de dépendances .

Voir mes diapositives pour Singletons en PHP - Pourquoi ils sont mauvais et comment vous pouvez les éliminer de vos applications pour plus d'informations.

Même Erich Gamma , l'un des inventeurs du modèle Singleton, doute de ce modèle de nos jours:

"Je suis pour abandonner Singleton. Son utilisation est presque toujours une odeur de design"

Lectures complémentaires

Si, après ce qui précède, vous avez encore besoin d'aide pour décider:

Diagramme de décision singleton

Gordon
la source
1
@Gordon oui. Et même s'il était possible de maintenir des objets entre les requêtes, les Singletons enfreignent toujours quelques principes SOLID et introduisent Global State.
Gordon
4
Désolé d'aller à contre-courant, mais DI n'est pas vraiment une solution au problème pour lequel Singleton est utilisé, à moins que vous ne vous contentiez d'avoir des classes avec 42 paramètres ctor (ou 42 appels setFoo () et setBar () nécessaires pour le faire travail). Oui, certaines applications, malheureusement, doivent être couplées et dépendent de beaucoup de choses externes. PHP est un langage de collage, et parfois il y a beaucoup de choses à coller ensemble.
StasM
14
@StasM si vous avez 42 paramètres ctor ou si vous avez besoin de beaucoup de setters, vous le faites mal. Regardez les discussions sur le code propre s'il vous plaît. Désolé, si je ne peux pas être dérangé d'expliquer cela encore une fois. N'hésitez pas à demander dans le chat PHP pour plus d'informations.
Gordon
@Gordon Où est la salle de chat php?
user658182
21

Qui a besoin de singletons en PHP?

Notez que presque toutes les objections aux singletons proviennent de points de vue techniques - mais elles sont également TRÈS limitées dans leur portée. Surtout pour PHP. Tout d'abord, je vais énumérer certaines des raisons d'utiliser des singletons, puis j'analyserai les objections à l'utilisation des singletons. Premièrement, les personnes qui en ont besoin:

- Les personnes qui codent un grand framework / base de code, qui sera utilisé dans de nombreux environnements différents, devront travailler avec différents frameworks / bases de code déjà existants, avec la nécessité de mettre en œuvre de nombreuses demandes différentes, changeantes, voire fantaisistes de la part des clients / patrons / direction / chefs d'unité le font.

Vous voyez, le modèle singleton est auto-inclusif. Une fois terminé, une classe singleton est rigide dans tout code dans lequel vous l'incluez et agit exactement comme vous avez créé ses méthodes et ses variables. Et c'est toujours le même objet dans une requête donnée. Puisqu'il ne peut pas être créé deux fois pour être deux objets différents, vous savez ce qu'est un objet singleton à un moment donné dans un code - même si le singleton est inséré dans deux, trois bases de code différentes, anciennes, voire spaghetti. Par conséquent, cela facilite les choses en termes de développement - même si de nombreuses personnes travaillent dans ce projet, lorsque vous voyez un singleton initialisé en un point dans une base de code donnée, vous savez ce que c'est, ce qu'il fait, comment il et l'état dans lequel il se trouve. S'il s'agissait de la classe traditionnelle, vous auriez besoin de garder une trace de l'endroit où cet objet a été créé pour la première fois, quelles méthodes y ont été invoquées jusqu'à ce point dans le code, et son état particulier. Mais, déposez un singleton là-bas, et si vous avez abandonné les méthodes de débogage et d'information appropriées et le suivi dans le singleton lors du codage, vous savez exactement ce que c'est. Donc, par conséquent, cela facilite la tâche aux personnes qui doivent travailler avec des bases de code différentes, avec la nécessité d'intégrer du code qui a été fait auparavant avec des philosophies différentes, ou fait par des personnes avec lesquelles vous n'avez aucun contact. (c'est-à-dire, fournisseur-projet-entreprise-quoi qu'il en soit, pas de support, rien). cela facilite la tâche des personnes qui doivent travailler avec des bases de code différentes, avec la nécessité d'intégrer du code qui a été fait auparavant avec des philosophies différentes, ou fait par des personnes avec lesquelles vous n'avez aucun contact. (c'est-à-dire, fournisseur-projet-entreprise-quoi qu'il en soit, pas de support, rien). cela facilite la tâche des personnes qui doivent travailler avec des bases de code différentes, avec la nécessité d'intégrer du code qui a été fait auparavant avec des philosophies différentes, ou fait par des personnes avec lesquelles vous n'avez aucun contact. (c'est-à-dire, fournisseur-projet-entreprise-quoi qu'il en soit, pas de support, rien).

- Les personnes qui ont besoin de travailler avec des API , des services et des sites Web tiers .

Si vous regardez de plus près, ce n'est pas trop différent du cas précédent: les API, services, sites Web tiers sont comme des bases de code externes et isolées sur lesquelles vous n'avez AUCUN contrôle. Tout peut arriver. Ainsi, avec une session / classe d'utilisateurs singleton, vous pouvez gérer TOUT type d'implémentation de session / autorisation de fournisseurs tiers comme OpenID , Facebook , Twitter et bien d'autres - et vous pouvez tout faire en même temps à partir du même objet singleton - qui est facilement accessible, dans un état connu à tout moment, quel que soit le code auquel vous le branchez. Vous pouvez même créer plusieurs sessions vers plusieurs API / services tiers différents pour le MÊME utilisateur dans votre propre site Web / application, et faire ce que vous voulez en faire.

Bien sûr, tout cela peut également être adapté aux méthodes traditionnelles en utilisant des classes et des objets normaux - le problème ici est que le singleton est plus ordonné, plus net et donc à cause de cela gérable / testable plus facile par rapport à l'utilisation traditionnelle de classe / objet dans de telles situations.

- Les personnes qui ont besoin d'un développement rapide

Le comportement global des singletons facilite la construction de tout type de code avec un framework qui a une collection de singletons sur lesquels construire, car une fois que vous avez bien construit vos classes singleton, les méthodes établies, matures et définies seront facilement disponibles et utilisable partout, à tout moment, de manière cohérente. Il faut du temps pour mûrir vos classes, mais après cela, elles sont solides, cohérentes et utiles. Vous pouvez avoir autant de méthodes dans un singleton faisant ce que vous voulez, et, bien que cela puisse augmenter l'empreinte mémoire de l'objet, cela apporte beaucoup plus d'économies de temps nécessaires pour un développement rapide - une méthode que vous n'utilisez pas dans une instance donnée de une application peut être utilisée dans une autre intégrée, et vous pouvez simplement appliquer une nouvelle fonctionnalité que le client / patron / chef de projet demande juste par quelques modifications.

Vous avez eu l'idée. Passons maintenant aux objections aux singletons et à la croisade impie contre quelque chose d'utile :

- La principale objection est que cela rend les tests plus difficiles.

Et vraiment, dans une certaine mesure, même si cela peut être facilement atténué en prenant les précautions appropriées et en codant des routines de débogage dans vos singletons AVEC la réalisation que vous allez déboguer un singleton. Mais voyez, ce n'est pas trop différent de TOUTE autre philosophie / méthode / modèle de codage qui existe - c'est juste que les singletons sont relativement nouveaux et peu répandus, de sorte que les méthodes de test actuelles finissent par être comparativement incompatibles avec eux. Mais ce n'est différent dans aucun aspect des langages de programmation - différents styles nécessitent des approches différentes.

Un point où cette objection tombe à plat en ce sens qu'elle ignore le fait que les raisons pour lesquelles les applications développées ne sont pas destinées à «tester», et que les tests ne sont pas la seule phase / processus qui entre dans le développement d'une application. Les applications sont développées pour une utilisation en production. Et comme je l'ai expliqué dans la section `` qui a besoin de singletons '', les singletons peuvent réduire considérablement la complexité de devoir faire fonctionner un code AVEC et À L'INTÉRIEUR de nombreuses bases de code / applications / services tiers différents. Le temps qui peut être perdu lors des tests est du temps gagné en développement et en déploiement. Ceci est particulièrement utile à cette époque d'authentification / d'application / d'intégration tierce - Facebook, Twitter, OpenID, bien d'autres et qui sait ce qui va suivre.

Bien que cela soit compréhensible, les programmeurs travaillent dans des circonstances très différentes en fonction de leur carrière. Et pour les personnes qui travaillent dans des entreprises relativement grandes avec des départements définis tendant des logiciels / applications différents et définis de manière confortable et sans la condamnation imminente de coupes budgétaires / licenciements et le besoin qui l'accompagne de faire BEAUCOUP de choses avec beaucoup de choses différentes dans une mode bon marché / rapide / fiable, les singletons peuvent ne pas sembler si nécessaires. Et cela peut même être une nuisance / un obstacle à ce qu'ils ont DÉJÀ.

Mais pour ceux qui ont besoin de travailler dans les tranchées sales du développement `` agile '', devant implémenter de nombreuses demandes différentes (parfois déraisonnables) de leur client / manager / projet, les singletons sont une grâce salvatrice pour des raisons expliquées précédemment.

- Une autre objection est que son empreinte mémoire est plus élevée

Parce qu'un nouveau singleton existera pour chaque requête de chaque client, cela PEUT être une objection pour PHP. Avec des singletons mal construits et utilisés, l'empreinte mémoire d'une application peut être plus élevée si de nombreux utilisateurs sont servis par l'application à un moment donné.

Cependant, cela est valable pour TOUT type d'approche que vous pouvez adopter lors du codage des choses. Les questions à se poser sont: les méthodes, les données qui sont détenues et traitées par ces singletons sont-elles inutiles? Car, si elles SONT nécessaires dans la plupart des requêtes que l'application reçoit, alors même si vous n'utilisez pas de singletons, ces méthodes et données SERONT présentes dans votre application sous une forme ou une autre via le code. Donc, tout devient une question de savoir combien de mémoire allez-vous économiser, lorsque vous initialisez un objet de classe traditionnel 1/3 dans le traitement du code et que vous le détruisez aux 3/4.

Voyez, lorsqu'elle est posée de cette façon, la question devient tout à fait hors de propos - il ne devrait pas y avoir de méthodes inutiles, de données contenues dans des objets dans votre code de toute façon - que vous utilisiez des singletons ou non. Donc, cette objection aux singletons devient vraiment hilarante en cela, elle suppose qu'il y aura des méthodes inutiles, des données dans les objets créés à partir des classes que vous utilisez.

- Certaines objections invalides telles que `` rend le maintien de plusieurs connexions de base de données impossible / plus difficile ''

Je ne peux même pas commencer à comprendre cette objection, quand tout ce dont on a besoin pour maintenir plusieurs connexions de base de données, plusieurs sélections de base de données, plusieurs requêtes de base de données, plusieurs ensembles de résultats dans un singleton donné est simplement de les garder dans des variables / tableaux dans le singleton aussi longtemps que ils sont nécessaires. Cela peut être aussi simple que de les conserver dans des tableaux, bien que vous puissiez inventer la méthode que vous souhaitez utiliser pour effectuer cela. Mais examinons le cas le plus simple, l'utilisation de variables et de tableaux dans un singleton donné:

Imaginez que ce qui suit est à l'intérieur d'un singleton de base de données donné:

$ this -> connections = array (); (mauvaise syntaxe, je l'ai juste tapée comme ceci pour vous donner l'image - la déclaration correcte de la variable est public $ connections = array (); et son utilisation est $ this-> connections ['connectionkey'] naturellement)

Vous pouvez configurer et conserver plusieurs connexions à tout moment dans un tableau de cette manière. Et il en va de même pour les requêtes, les ensembles de résultats, etc.

$ this -> query (QUERYSTRING, 'queryname', $ this-> connections ['particulrconnection']);

Ce qui peut simplement faire une requête à une base de données sélectionnée avec une connexion sélectionnée, et simplement stocker dans votre

$ this -> résultats

tableau avec la clé 'queryname'. Bien sûr, vous devrez avoir votre méthode de requête codée pour cela - ce qui est simple à faire.

Cela vous permet de maintenir un nombre pratiquement infini de connexions de base de données et d'ensembles de résultats différents (autant que les limites de ressources le permettent bien sûr) autant que vous en avez besoin. Et ils sont disponibles pour N'IMPORTE QUEL morceau de code en un point donné de n'importe quelle base de code donnée dans laquelle cette classe singleton a été instanciée.

Bien sûr, vous auriez naturellement besoin de libérer les ensembles de résultats et les connexions lorsque cela n'est pas nécessaire - mais cela va sans dire, et ce n'est pas spécifique aux singletons ou à toute autre méthode / style / concept de codage.

À ce stade, vous pouvez voir comment vous pouvez gérer plusieurs connexions / états à des applications ou services tiers dans le même singleton. Pas si différent.

Bref, en fin de compte, les modèles singleton ne sont qu'une autre méthode / style / philosophie pour programmer, et ils sont aussi utiles que TOUT autre lorsqu'ils sont utilisés au bon endroit, de la manière correcte. Ce qui n'est différent de rien.

Vous remarquerez que dans la plupart des articles dans lesquels les singletons sont critiqués, vous verrez également des références à des «globaux» qui sont «mauvais».

Regardons les choses en face - tout ce qui n'est pas utilisé correctement, maltraité, mal utilisé, EST mal. Cela ne se limite à aucun langage, aucun concept de codage, aucune méthode. Chaque fois que vous voyez quelqu'un émettre des déclarations générales comme «X is evil», fuyez cet article. Il y a de fortes chances que ce soit le produit d'un point de vue limité - même si le point de vue est le résultat d'années d'expérience dans quelque chose de particulier - qui finit généralement par être le résultat d'un travail excessif dans un style / méthode donné - conservatisme intellectuel typique.

Des exemples sans fin peuvent être donnés pour cela, allant de «les globaux sont mauvais» à «les iframes sont mauvais». Il y a environ 10 ans, même proposer l'utilisation d'une iframe dans une application donnée était une hérésie. Ensuite vient Facebook, des iframes partout, et regardez ce qui s'est passé - les iframes ne sont plus si maléfiques.

Il y a encore des gens qui insistent obstinément sur le fait qu'ils sont `` mauvais '' - et parfois pour de bonnes raisons aussi - mais, comme vous pouvez le voir, il y a un besoin, les iframes remplissent ce besoin et fonctionnent bien, et par conséquent, le monde entier continue de bouger.

L'atout principal d'un programmeur / codeur / ingénieur logiciel est un esprit libre, ouvert et flexible.

unité100
la source
2
-1. Bien que je convienne que le fait d'avoir un esprit ouvert et flexible est un atout indispensable pour tout développeur, cela ne rachète pas le Singleton d'être un Antipattern. La réponse ci-dessus contient tellement de déclarations inexactes et de conclusions erronées sur la nature et les effets du Singleton que je ne peux que la rejeter.
Gordon
-1. J'ai dû faire l'expérience d'un framework avec de nombreux singletons de première main et les tests automatiques sont impossibles. Je dois tout tester manuellement par essais et erreurs dans un navigateur. Certaines erreurs peuvent être évitées grâce à la révision du code (orthographe, erreurs de syntaxe) mais les erreurs fonctionnelles sont souvent masquées. Ces tests nécessitent beaucoup plus de temps que les tests unitaires. Avec les tests unitaires, je pourrais dire: cette classe fonctionne de manière isolée, l'erreur doit être ailleurs. Sans le débogage, c'est fastidieux.
Jim Martens
Le cadre devait intégrer la journalisation et le suivi des erreurs. En outre, une classe fonctionnant correctement de manière isolée fonctionnerait également correctement sous une forme singleton lorsqu'elle était placée dans une application plus large. Ce qui signifie que dans ce cas, ce qui est cassé serait une autre classe ou fonction qui interagit avec ce singleton. Ce n'est pas différent du suivi de bogue ordinaire dans une grande application. Ce qui est en soi assez difficile sans que l'application ait une journalisation appropriée.
unity100
Inexacte. Des tonnes de singletones est définitivement MAUVAIS, car cela crée Testing-HELL. :-) Cependant, un singletone par application peut être bon. Par exemple: en tant que fonctionnalité de journalisation unifiée - à mettre en œuvre dans toutes les applications (y compris certaines applications à code hérité).
Filip OvertoneSinger Rydlo
"Le temps qui peut être perdu dans les tests ..." C'est vraiment une très mauvaise pratique et façon de penser. Toutes ces applications héritées ont été développées dans cet esprit et il est devenu impossible de les maintenir, elles devaient donc être réécrites. S'il n'y a pas de tests, le temps sera perdu lorsqu'une nouvelle fonctionnalité est développée et casse quelque chose dans une autre partie du système. Temps perdu lors du débogage, temps perdu par les utilisateurs qui peuvent utiliser cette fonctionnalité correctement, confiance dans l'application perdue, etc.
Bogdancep
15

Les singletons sont considérés par beaucoup comme des anti-patterns car ils ne sont en réalité que des variables globales glorifiées. En pratique, il existe relativement peu de scénarios où il est nécessaire pour une classe d'avoir une seule instance; généralement, c'est juste qu'une seule instance suffit , auquel cas l'implémentation en tant que singleton est complètement inutile.

Pour répondre à la question, vous avez raison de dire que les singletons sont exagérés ici. Une simple variable ou fonction fera l'affaire. Une meilleure approche (plus robuste), cependant, serait d'utiliser l' injection de dépendances pour supprimer complètement le besoin de variables globales.

Will Vousden
la source
Mais les singletons peuvent se dégrader très facilement en DI, les classes statiques ne le peuvent pas, ce qui est le vrai problème avec les classes statiques.
Bill K le
@Bill: Très vrai, mais c'est pourquoi je préconiserais une approche DI pour commencer, plutôt que des fonctions lâches ou des méthodes statiques :)
Will Vousden
Dans certains langages (tels que Java), les classes statiques (ou méthodes statiques de classes) ne peuvent pas être étendues. Vous créez donc des problèmes potentiels (ou au mieux, plus de travail) pour les futurs développeurs. Ainsi, certains suggèrent que les méthodes statiques devraient être généralement évitées à moins que vous n'en ayez un besoin spécifique.
Marvo
8

Dans votre exemple, vous avez affaire à une seule information apparemment inchangée. Pour cet exemple, un Singleton serait exagéré et simplement utiliser une fonction statique dans une classe fera très bien l'affaire.

Autres réflexions: Vous pourriez être confronté à un cas d'implémentation de modèles pour le plaisir de modèles et votre instinct vous dit "non, vous n'êtes pas obligé" pour les raisons que vous avez énoncées.

MAIS: Nous n'avons aucune idée de la taille et de la portée de votre projet. S'il s'agit de code simple, peut-être jeté, qui n'aura probablement pas besoin de changer, alors oui, allez-y et utilisez des membres statiques. Mais, si vous pensez que votre projet devra peut-être évoluer ou être préparé pour le codage de maintenance, alors oui, vous voudrez peut-être utiliser le modèle Singleton.

Paul Sasik
la source
1
Wow, tout simplement faux. Le point entier de la différence (la réponse à la question) est combien il est plus difficile de corriger plus tard votre code pour ajouter une deuxième instance. C'est beaucoup plus difficile à faire si vous avez utilisé des méthodes statiques. C'est comme dire "Les globaux vont bien dans vos conditions limitées" alors que tout le problème avec Globals est que les conditions changent.
Bill K le
@Bill K: Je suis d'accord avec vous et j'utiliserais un singleton s'il y avait de la complexité. Mais j'essayais de répondre à la question du point de vue du PO et j'ai pensé, eh bien, oui, je suppose que c'est exagéré dans ce cas très limité. Bien sûr, j'ignorais les problèmes d'architecture ou d'évolutivité et une tonne d'autres considérations. Aurais-je dû inclure cela comme une mise en garde dans ma réponse avec une explication sur la raison pour laquelle quelqu'un devrait toujours utiliser un singleton ... ce qui aurait certainement provoqué des votes négatifs de la part des autres?
Paul Sasik le
5

Tout d'abord, je veux juste dire que je ne trouve pas beaucoup d'utilisations au modèle Singleton. Pourquoi voudrait-on conserver un seul objet dans toute l'application? Surtout pour les bases de données, que faire si je veux me connecter à un autre serveur de base de données? Je dois me déconnecter et me reconnecter à chaque fois ...? En tous cas...

Il y a plusieurs inconvénients à l'utilisation de globals dans une application (ce que fait l'utilisation traditionnelle du modèle Singleton):

  • Difficile à tester unitaire
  • Problèmes d'injection de dépendance
  • Peut créer des problèmes de verrouillage (application multithread)

Utiliser des classes statiques au lieu d'une instance de singleton présente également certains des mêmes inconvénients, car le plus gros problème du singleton est la getInstanceméthode statique .

Vous pouvez limiter le nombre d'instances qu'une classe peut avoir sans utiliser la getInstanceméthode traditionnelle :

class Single {

    static private $_instance = false;

    public function __construct() {
        if (self::$_instance)
           throw new RuntimeException('An instance of '.__CLASS__.' already exists');

        self::$_instance = true;
    }

    private function __clone() {
        throw new RuntimeException('Cannot clone a singleton class');
    }

    public function __destruct() {
        self::$_instance = false;
    }

}

$a = new Single;
$b = new Single; // error
$b = clone($a); // error
unset($a);
$b = new Single; // works

Cela aidera sur les premiers points mentionnés ci-dessus: les tests unitaires et l'injection de dépendances; tout en vous assurant qu'une seule instance de la classe existe dans votre application. Vous pouvez, par exemple, simplement transmettre l'objet résultant à vos modèles (modèle MVC) pour qu'ils les utilisent.

netcoder
la source
5

Considérez simplement en quoi votre solution diffère de celle présentée dans la documentation PHP. En fait, il n'y a qu'une "petite" différence: votre solution fournit une PDOinstance aux appelants du getter , tandis que celle de la documentation fournit aux appelants de Database::singletonune Databaseinstance (ils utilisent ensuite le getter pour obtenir une PDOinstance).

Alors à quelle conclusion arrivons-nous?

  • Dans le code de la documentation, les appelants obtiennent une Databaseinstance. La Databaseclasse peut exposer (en fait, elle devrait exposer si vous allez à tous ces problèmes) une interface plus riche ou de plus haut niveau que l' PDOobjet qu'elle enveloppe.
  • Si vous modifiez votre implémentation pour renvoyer un autre type (plus riche) que PDO, alors les deux implémentations sont équivalentes. Il n'y a aucun avantage à suivre la mise en œuvre manuelle.

Sur le plan pratique, Singleton est un modèle assez controversé. C'est principalement parce que:

  • C'est surutilisé. Les programmeurs novices grok Singleton beaucoup plus facilement qu'ils ne grokent d'autres patterns. Ils appliquent ensuite leurs nouvelles connaissances partout, même si le problème en question peut être mieux résolu sans Singleton (quand vous tenez un marteau, tout ressemble à un clou).
  • Selon le langage de programmation, implémenter un Singleton de manière étanche et sans fuite peut s'avérer être une tâche titanesque (surtout si nous avons des scénarios avancés: un singleton dépendant d'un autre singleton, des singletons qui peuvent être détruits et recréés, etc. ). Essayez simplement de rechercher l'implémentation "définitive" de Singleton en C ++, je vous mets au défi (je possède le design révolutionnaire C ++ moderne d'Andrei Alexandrescu, qui documente une grande partie du désordre).
  • Il impose une charge de travail supplémentaire à la fois lors du codage du Singleton et lors de l'écriture de code pour y accéder, charge de travail dont vous pouvez vous passer en suivant quelques contraintes auto-imposées sur ce que vous essayez de faire avec vos variables de programme.

Donc, comme conclusion finale: votre singleton va très bien. Ne pas utiliser du tout Singleton est également très bien la plupart du temps.

Jon
la source
2

Votre interprétation est correcte. Les singletons ont leur place mais sont surutilisés. Souvent, l'accès aux fonctions membres statiques est suffisant (notamment, lorsque vous n'avez pas besoin de contrôler le temps de construction de quelque manière que ce soit). Mieux, vous pouvez simplement mettre des fonctions et des variables libres dans un espace de noms.

Courses de légèreté en orbite
la source
2

Lors de la programmation, il n'y a ni «bien» ni «mal»; il y a «bonne pratique» et «mauvaise pratique».

Les singletons sont généralement créés en tant que classe pour être réutilisés plus tard. Ils doivent être créés de manière à ce que le programmeur n'instancie pas accidentellement deux instances tout en codant ivre à minuit.

Si vous avez une petite classe simple qui ne devrait pas être instanciée plus d'une fois, vous n'avez pas besoin d'en faire un singleton. C'est juste un filet de sécurité si vous le faites.

ce n'est pas toujours une mauvaise pratique d'avoir des objets globaux. Si vous savez que vous allez l'utiliser globalement / partout / tout le temps, cela peut être l'une des rares exceptions. Cependant, les globaux sont généralement considérés comme des «mauvaises pratiques» de la même manière que gotodes mauvaises pratiques.

zzzzBov
la source
2

Je ne vois aucun intérêt à cela. Si vous implémentiez la classe de telle sorte que la chaîne de connexion soit prise comme paramètre du constructeur et que vous mainteniez une liste d' objets PDO (un pour chaque chaîne de connexion unique), alors peut-être y aurait-il un avantage, mais l'implémentation de singleton dans cet exemple semble être un exercice inutile.

Kell
la source
1

Vous ne manquez rien, pour autant que je sache. L'exemple est assez imparfait. Cela ferait une différence si la classe singleton avait des variables d'instance non statiques.

FooLman
la source