Accedo a mi base de datos MySQL a través de PDO. Estoy configurando el acceso a la base de datos, y mi primer intento fue usar lo siguiente:
Lo primero que pensé es global
:
$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd');
function some_function() {
global $db;
$db->query('...');
}
Esto se considera una mala práctica. Después de una pequeña búsqueda, terminé con el patrón Singleton , que
"se aplica a situaciones en las que debe haber una sola instancia de una clase".
De acuerdo con el ejemplo en el manual, debemos hacer esto:
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();
¿Por qué necesito esa clase relativamente grande cuando puedo hacer esto?
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();
Este último funciona perfectamente y no tengo que preocuparme $db
más.
¿Cómo puedo crear una clase singleton más pequeña, o hay un caso de uso para singletons que me falta en PHP?
php
oop
design-patterns
singleton
seriousdev
fuente
fuente
Respuestas:
Bien, me pregunté sobre eso por un tiempo cuando comencé mi carrera. Lo implementé de diferentes maneras y se me ocurrieron dos razones para elegir no usar clases estáticas, pero son bastante importantes.
Una es que muy a menudo encontrarás algo de lo que estás absolutamente seguro de que nunca tendrás más de una instancia, eventualmente tendrás una segunda. Puede terminar con un segundo monitor, una segunda base de datos, un segundo servidor, lo que sea.
Cuando esto sucede, si ha usado una clase estática, se encontrará con un refactor mucho peor que si hubiera usado un singleton. Un singleton es un patrón dudoso en sí mismo, pero se convierte con bastante facilidad en un patrón de fábrica inteligente, incluso se puede convertir para usar la inyección de dependencia sin demasiados problemas. Por ejemplo, si su singleton se obtiene a través de getInstance (), puede cambiarlo fácilmente a getInstance (databaseName) y permitir múltiples bases de datos, sin otros cambios de código.
El segundo problema es la prueba (y, sinceramente, esto es lo mismo que el primer problema). A veces, desea reemplazar su base de datos con una base de datos simulada. En efecto, esta es una segunda instancia del objeto de base de datos. Esto es mucho más difícil de hacer con las clases estáticas que con un singleton, solo tiene que burlarse del método getInstance (), no todos los métodos en una clase estática (que en algunos idiomas puede ser muy difícil).
Realmente se reduce a los hábitos, y cuando la gente dice que los "Globales" son malos, tienen muy buenas razones para decirlo, pero puede que no siempre sea obvio hasta que usted mismo haya abordado el problema.
Lo mejor que puede hacer es preguntar (como lo hizo), luego hacer una elección y observar las ramificaciones de su decisión. Tener el conocimiento para interpretar la evolución de su código a lo largo del tiempo es mucho más importante que hacerlo bien en primer lugar.
fuente
getInstance(databaseName)
simplemente dispersar referencias a un repositorio global de instancias en todo su código? El código que llamaríagetInstance
debería tener las instancias inyectadas en él por el código del cliente, por lo que no debería necesitar llamargetInstance
en primer lugar.Los Singletons tienen muy poco uso, si no es que no, en PHP.
En los idiomas donde los objetos viven en la memoria compartida, Singletons se puede utilizar para mantener bajo el uso de memoria. En lugar de crear dos objetos, hace referencia a una instancia existente desde la memoria de la aplicación compartida globalmente. En PHP no existe tal memoria de aplicación. Un Singleton creado en una Solicitud vive exactamente para esa solicitud. Un Singleton creado en otra Solicitud realizada al mismo tiempo sigue siendo una instancia completamente diferente. Por lo tanto, uno de los dos propósitos principales de un Singleton no es aplicable aquí.
Además, muchos de los objetos que pueden existir conceptualmente solo una vez en su aplicación no requieren necesariamente un mecanismo de lenguaje para hacer cumplir esto. Si solo necesita una instancia, no cree una instancia de otra . Solo cuando no tenga otra instancia, por ejemplo, cuando los gatitos mueren cuando crea una segunda instancia, es posible que tenga un caso de uso válido para un Singleton.
El otro propósito sería tener un punto de acceso global a una instancia dentro de la misma Solicitud. Si bien esto puede sonar deseable, realmente no lo es, porque crea un acoplamiento al alcance global (como cualquier global y estática). Esto hace que las pruebas unitarias sean más difíciles y que su aplicación en general sea menos mantenible. Hay formas de mitigar esto, pero en general, si necesita tener la misma instancia en muchas clases, use la inyección de dependencia .
Vea mis diapositivas para Singletons en PHP: por qué son malas y cómo puede eliminarlas de sus aplicaciones para obtener información adicional.
Incluso Erich Gamma , uno de los inventores del patrón Singleton, duda de este patrón hoy en día:
Otras lecturas
Si, después de lo anterior, aún necesita ayuda para decidir:
fuente
¿Quién necesita singletons en PHP?
Tenga en cuenta que casi todas las objeciones a los singletons provienen de puntos de vista técnicos, pero también tienen un alcance MUY limitado. Especialmente para PHP. Primero, enumeraré algunas de las razones para usar singletons, y luego analizaré las objeciones al uso de singletons. Primero, las personas que los necesitan:
- Las personas que están codificando un gran marco / base de código, que se utilizará en muchos entornos diferentes, tendrán que trabajar con marcos / bases de código diferentes previamente existentes, con la necesidad de implementar muchas solicitudes diferentes, cambiantes e incluso caprichosas de clientes / jefes / gestión / líderes de la unidad lo hacen.
Mira, el patrón singleton es auto inclusivo. Cuando se hace, una clase singleton es rígida en cualquier código en el que la incluya, y actúa exactamente como creó sus métodos y variables. Y siempre es el mismo objeto en una solicitud dada. Como no se puede crear dos veces para que sean dos objetos diferentes, usted sabe lo que es un objeto singleton en cualquier punto dado de un código, incluso si el singleton se inserta en dos, tres bases de códigos de espagueti diferentes, antiguas e incluso. Por lo tanto, lo hace más fácil en términos de propósitos de desarrollo, incluso si hay muchas personas trabajando en ese proyecto, cuando ve que un singleton se inicializa en un punto en cualquier base de código dada, sabe qué es, qué hace, cómo funciona. lo hace, y el estado en el que se encuentra. Si se tratara de la clase tradicional, debería realizar un seguimiento de dónde se creó ese objeto por primera vez, qué métodos se invocaron en él hasta ese punto en el código, y su estado particular. Pero, suelte un singleton allí, y si eliminó los métodos adecuados de depuración e información y el seguimiento en el singleton mientras lo codifica, sabrá exactamente qué es. Por lo tanto, hace que sea más fácil para las personas que tienen que trabajar con diferentes bases de código, con la necesidad de integrar el código que se hizo anteriormente con diferentes filosofías, o hecho por personas con las que no tienes contacto. (es decir, proveedor-proyecto-empresa-lo que sea que no haya más, no hay soporte, nada). hace que sea más fácil para las personas que tienen que trabajar con diferentes bases de código, con la necesidad de integrar el código que se hizo anteriormente con diferentes filosofías, o hecho por personas con las que no tienes contacto. (es decir, proveedor-proyecto-empresa-lo que sea que no haya más, no hay soporte, nada). hace que sea más fácil para las personas que tienen que trabajar con diferentes bases de código, con la necesidad de integrar el código que se hizo anteriormente con diferentes filosofías, o hecho por personas con las que no tienes contacto. (es decir, proveedor-proyecto-empresa-lo que sea que no haya más, no hay soporte, nada).
- Personas que necesitan trabajar con API , servicios y sitios web de terceros .
Si observa más de cerca, esto no es muy diferente al caso anterior: las API, servicios y sitios web de terceros son como bases de código externas y aisladas sobre las cuales NO tiene control. Cualquier cosa puede suceder. Por lo tanto, con una clase de sesión / usuario de singleton, puede administrar CUALQUIER tipo de implementación de sesión / autorización de proveedores externos como OpenID , Facebook , Twitter y muchos más, y puede hacer TODOS al mismo tiempo desde el MISMO objeto singleton - que es fácilmente accesible, en un estado conocido en cualquier punto dado en cualquier código en el que lo conecte. Incluso puede crear múltiples sesiones para múltiples API / servicios de terceros diferentes para el MISMO usuario en su propio sitio web / aplicación, y hacer lo que quiera hacer con ellos.
Por supuesto, todo esto también puede ser tono con los métodos tradicionales mediante el uso de clases y objetos normales: el problema aquí es que singleton es más ordenado, más ordenado y, por lo tanto, es más fácil de manejar / probar en comparación con el uso tradicional de clase / objeto en tales situaciones.
- Las personas que necesitan un desarrollo rápido.
El comportamiento global de los singletons facilita la creación de cualquier tipo de código con un marco que tiene una colección de singletons para construir, porque una vez que construye bien sus clases de singleton, los métodos establecidos, maduros y establecidos estarán fácilmente disponibles y Se puede usar en cualquier lugar, en cualquier momento, de manera consistente. Lleva algún tiempo madurar tus clases, pero después de eso, son sólidas, consistentes y útiles. Puede tener tantos métodos en un singleton haciendo lo que quiera, y, aunque esto puede aumentar la huella de memoria del objeto, trae mucho más ahorro de tiempo requerido para un desarrollo rápido, un método que no está utilizando en una instancia determinada de una aplicación se puede usar en otra integrada, y puede simplemente aplicar una nueva función que el cliente / jefe / gerente de proyecto solicita con solo algunas modificaciones.
Tienes la idea. Ahora pasemos a las objeciones a los solteros y la cruzada impía contra algo que es útil :
- La principal objeción es que dificulta las pruebas.
Y realmente, lo hace hasta cierto punto, incluso si puede mitigarse fácilmente tomando las precauciones adecuadas y codificando rutinas de depuración en sus singletons CON la constatación de que va a depurar un singleton. Pero vea, esto no es muy diferente de CUALQUIER otra filosofía / método / patrón de codificación que exista, es solo que, los singletons son relativamente nuevos y no están muy extendidos, por lo que los métodos de prueba actuales terminan siendo incompatibles con ellos. Pero eso no es diferente en ningún aspecto de los lenguajes de programación: diferentes estilos requieren diferentes enfoques.
Un punto en el que esta objeción cae en el plano, ignora el hecho de que las razones por las que las aplicaciones desarrolladas no son para 'probar', y las pruebas no son la única fase / proceso que entra en el desarrollo de una aplicación. Las aplicaciones se desarrollan para uso en producción. Y como expliqué en la sección 'quién necesita los singletons', los singletons pueden llegar a un GRAN acuerdo debido a la complejidad de tener que hacer que un código funcione DENTRO y DENTRO de muchas bases de código / aplicaciones / servicios de terceros diferentes. El tiempo que puede perderse en las pruebas es el tiempo ganado en el desarrollo y la implementación. Esto es especialmente útil en esta era de autenticación / aplicación / integración de terceros: Facebook, Twitter, OpenID, muchos más y quién sabe qué sigue.
Aunque es comprensible, los programadores trabajan en circunstancias muy diferentes dependiendo de su carrera. Y para las personas que trabajan en empresas relativamente grandes con departamentos definidos que atienden software / aplicaciones diferentes y definidas de manera cómoda y sin la condena inminente de recortes / despidos presupuestarios y la necesidad de hacer MUCHAS cosas con muchas cosas diferentes en una manera barata / rápida / confiable, los singletons pueden no parecer tan necesarios. E incluso puede ser una molestia / impedimento para lo que YA tienen.
Pero para aquellos que necesitan trabajar en las trincheras sucias del desarrollo 'ágil', tener que implementar muchas solicitudes diferentes (a veces irrazonables) de su cliente / gerente / proyecto, los singletons son una gracia salvadora debido a razones explicadas anteriormente.
- Otra objeción es que su huella de memoria es mayor
Como existirá un nuevo singleton para cada solicitud de cada cliente, esto PUEDE ser una objeción para PHP. Con singletons mal construidos y usados, la huella de memoria de una aplicación puede ser mayor si la aplicación sirve a muchos usuarios en un punto dado.
Sin embargo, esto es válido para CUALQUIER tipo de enfoque que pueda adoptar al codificar cosas. Las preguntas que deben formularse son: ¿son innecesarios los métodos, los datos que se guardan y procesan estos singletons? Porque, si SON necesarios en muchas de las solicitudes que recibe la aplicación, incluso si no usa singletons, esos métodos y datos ESTARÁN presentes en su aplicación de una forma u otra a través del código. Por lo tanto, todo se convierte en una cuestión de cuánta memoria va a guardar, cuando inicializa un objeto de clase tradicional 1/3 en el procesamiento del código y lo destruye 3/4 en él.
Vea, cuando se pone de esta manera, la pregunta se vuelve bastante irrelevante: no debe haber métodos innecesarios, datos almacenados en objetos en su código en CUALQUIER forma, independientemente de si usa singletons o no. Entonces, esta objeción a los singletons se vuelve realmente graciosa porque ASUME que habrá métodos innecesarios, datos en los objetos creados a partir de las clases que usa.
- Algunas objeciones no válidas como 'hace que el mantenimiento de múltiples conexiones de bases de datos sea imposible / difícil'
Ni siquiera puedo comenzar a comprender esta objeción, cuando todo lo que uno necesita para mantener múltiples conexiones de bases de datos, múltiples selecciones de bases de datos, múltiples consultas de bases de datos, múltiples conjuntos de resultados en un singleton dado es solo mantenerlos en variables / matrices en el singleton siempre que son necesarios Esto puede ser tan simple como mantenerlos en matrices, aunque puede inventar cualquier método que desee utilizar para lograrlo. Pero examinemos el caso más simple, el uso de variables y matrices en un singleton dado:
Imagine que lo siguiente está dentro de una base de datos dada singleton:
$ this -> connections = array (); (sintaxis incorrecta, simplemente lo escribí así para darle la imagen: la declaración adecuada de la variable es public $ connections = array (); y su uso es $ this-> connections ['connectionkey'] naturalmente)
Puede configurar y mantener múltiples conexiones en un momento dado en una matriz de esta manera. Y lo mismo ocurre con las consultas, los conjuntos de resultados, etc.
$ this -> query (QUERYSTRING, 'queryname', $ this-> connections ['particulrconnection']);
Que solo puede hacer una consulta a una base de datos seleccionada con una conexión seleccionada, y simplemente almacenarla en su
$ this -> resultados
matriz con la clave 'queryname'. Por supuesto, necesitará tener su método de consulta codificado para esto, lo cual es trivial.
Esto le permite mantener un número prácticamente infinito de (tanto como los límites de recursos lo permiten, por supuesto) diferentes conexiones de bases de datos y conjuntos de resultados tanto como los necesite. Y están disponibles para CUALQUIER pieza de código en cualquier punto dado en cualquier base de código dada en la que se haya instanciado esta clase singleton.
Por supuesto, naturalmente necesitaría liberar los conjuntos de resultados y las conexiones cuando no sea necesario, pero eso es evidente, y no es específico para singletons o cualquier otro método / estilo / concepto de codificación.
En este punto, puede ver cómo puede mantener múltiples conexiones / estados a aplicaciones o servicios de terceros en el mismo singleton. No tan diferente
En pocas palabras, al final, los patrones singleton son solo otro método / estilo / filosofía para programar, y son tan útiles como CUALQUIER otro cuando se usan en el lugar correcto, de la manera correcta. Lo cual no es diferente de nada.
Notarás que en la mayoría de los artículos en los que se critican los singletons, también verás referencias a que 'globals' son 'malvados'.
Seamos realistas: CUALQUIER cosa que no se usa correctamente, se abusa, se maltrata, ES maldad. Eso no se limita a ningún idioma, ningún concepto de codificación, ningún método. Cada vez que vea a alguien emitiendo declaraciones generales como 'X es malvado', huya de ese artículo. Hay muchas posibilidades de que sea producto de un punto de vista limitado, incluso si el punto de vista es el resultado de años de experiencia en algo en particular, lo que generalmente termina siendo el resultado de trabajar demasiado en un estilo / método dado, el conservadurismo intelectual típico.
Se pueden dar innumerables ejemplos para eso, que van desde 'los globales son malvados' hasta 'los iframes son malos'. Hace unos 10 años, incluso proponer el uso de un iframe en cualquier aplicación era herejía. Luego viene Facebook, iframes en todas partes, y mira lo que ha sucedido: los iframes ya no son tan malvados.
Todavía hay personas que insisten obstinadamente en que son 'malvados', y a veces también por buenas razones, pero, como puede ver, existe una necesidad, los iframes satisfacen esa necesidad y funcionan bien, y por lo tanto, el mundo entero simplemente sigue adelante.
El principal activo de un programador / codificador / ingeniero de software es una mente libre, abierta y flexible.
fuente
Muchos consideran que los singletons son antipatrones, ya que en realidad son solo variables globales glorificadas. En la práctica, hay relativamente pocos escenarios en los que es necesario que una clase tenga solo una instancia; por lo general, es solo que una instancia es suficiente , en cuyo caso implementarlo como un singleton es completamente innecesario.
Para responder a la pregunta, tienes razón en que los singletons son excesivos aquí. Una variable o función simple servirá. Sin embargo, un enfoque mejor (más sólido) sería utilizar la inyección de dependencia para eliminar la necesidad de variables globales por completo.
fuente
En su ejemplo, se trata de una sola pieza de información aparentemente inmutable. Para este ejemplo, un Singleton sería excesivo y solo usar una función estática en una clase funcionará bien.
Más pensamientos: es posible que esté experimentando un caso de implementación de patrones por el bien de los patrones y su instinto le dice "no, no tiene que hacerlo" por las razones que explicó.
PERO: No tenemos idea del tamaño y alcance de su proyecto. Si se trata de un código simple, tal vez descartarlo, que probablemente no necesite cambiar, entonces sí, continúe y use miembros estáticos. Pero, si cree que su proyecto podría necesitar escalar o estar preparado para la codificación de mantenimiento en el futuro, sí, es posible que desee utilizar el patrón Singleton.
fuente
Primero, solo quiero decir que no encuentro muchos usos para el patrón Singleton. ¿Por qué querría mantener un solo objeto en toda la aplicación? Especialmente para las bases de datos, ¿qué sucede si quiero conectarme a otro servidor de bases de datos? Tengo que desconectar y volver a conectar cada vez ...? De todas formas...
Existen varios inconvenientes para usar globals en una aplicación (que es lo que hace el uso tradicional del patrón Singleton):
Usar clases estáticas en lugar de una instancia de singleton también proporciona algunos de los mismos inconvenientes, porque el mayor problema de singleton es la estática
getInstance
método .Puede limitar el número de instancias que puede tener una clase sin usar el
getInstance
método tradicional :Esto ayudará en los primeros puntos mencionados anteriormente: prueba de unidad e inyección de dependencia; mientras se asegura de que exista una sola instancia de la clase en su aplicación. Podría, por ejemplo, simplemente pasar el objeto resultante a sus modelos (patrón MVC) para que lo usen.
fuente
Considere simplemente cómo su solución difiere de la presentada en los documentos PHP. De hecho, solo hay una "pequeña" diferencia: su solución proporciona una
PDO
instancia a las personas que llaman con el getter , mientras que la de los documentos proporcionaDatabase::singleton
unaDatabase
instancia a las personas que llaman (luego usan el getter para obtener unPDO
instancia).Entonces, ¿a qué conclusión llegamos?
Database
instancia. LaDatabase
clase puede exponer (de hecho, debería exponer si tiene todos estos problemas) una interfaz más rica o de nivel superior que laPDO
objeto que envuelve.PDO
, las dos implementaciones son equivalentes. No se obtiene ninguna ganancia al seguir la implementación manual.En el lado práctico, Singleton es un patrón bastante controvertido. Esto se debe principalmente a que:
Entonces, como conclusión final: su singleton está bien. No usar Singleton está bien la mayor parte del tiempo también.
fuente
Tu interpretación es correcta. Los solteros tienen su lugar pero se usan en exceso. A menudo, acceder a las funciones miembro estáticas es suficiente (especialmente cuando no es necesario controlar el tiempo de construcción de ninguna manera). Mejor, simplemente puede poner algunas funciones y variables libres en un espacio de nombres.
fuente
Cuando se programa no hay "correcto" ni "incorrecto"; hay "buenas prácticas" y "malas prácticas".
Los singletons generalmente se crean como una clase para ser reutilizados más tarde. Deben crearse de tal manera que el programador no cree accidentalmente dos instancias mientras codifica borracho a medianoche.
Si tiene una pequeña clase simple que no debe ser instanciada más de una vez, no necesita que sea un singleton. Es solo una red de seguridad si lo haces.
No siempre es una mala práctica tener objetos globales. Si sabe que lo va a usar globalmente / en todas partes / todo el tiempo, puede ser una de las pocas excepciones. Sin embargo, los globales generalmente se consideran "malas prácticas" de la misma manera que
goto
se consideran malas prácticas.fuente
No veo ningún punto para esto en absoluto. Si implementó la clase de tal manera que la cadena de conexión se tomó como un parámetro para el constructor y mantuvo una lista de objetos PDO (uno para cada cadena de conexión única), entonces tal vez habría algún beneficio, pero la implementación de singleton en Esta instancia parece un ejercicio inútil.
fuente
No te falta nada, por lo que puedo ver. El ejemplo es bastante defectuoso. Sería diferente si la clase singleton tuviera algunas variables de instancia no estáticas.
fuente