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?
la source
Réponses:
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.
la source
getInstance(databaseName)
dispersion des références à un référentiel global d'instances dans tout votre code? Le code qui appelleraitgetInstance
devrait avoir la ou les instances injectées par le code client, et ne devrait donc pas avoir besoin d'appelergetInstance
en premier lieu.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:
Lectures complémentaires
Si, après ce qui précède, vous avez encore besoin d'aide pour décider:
la source
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.
la source
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.
la source
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.
la source
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):
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
getInstance
méthode statique .Vous pouvez limiter le nombre d'instances qu'une classe peut avoir sans utiliser la
getInstance
méthode traditionnelle :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.
la source
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
PDO
instance aux appelants du getter , tandis que celle de la documentation fournit aux appelants deDatabase::singleton
uneDatabase
instance (ils utilisent ensuite le getter pour obtenir unePDO
instance).Alors à quelle conclusion arrivons-nous?
Database
instance. LaDatabase
classe 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'PDO
objet qu'elle enveloppe.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:
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.
la source
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.
la source
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
goto
des mauvaises pratiques.la source
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.
la source
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.
la source