¿Hay un caso de uso para singletons con acceso a la base de datos en PHP?

138

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 $dbmá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?

seriousdev
fuente
Hay muchos recursos y debates en esta pregunta relacionada: '¿Qué tienen de malo los singletons?'
FruitBreak

Respuestas:

80

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.

Bill K
fuente
15
Usted dice que los singletons se degradan muy bien a DI, pero ¿no es su ejemplo de getInstance(databaseName)simplemente dispersar referencias a un repositorio global de instancias en todo su código? El código que llamaría getInstancedebería tener las instancias inyectadas en él por el código del cliente, por lo que no debería necesitar llamar getInstanceen primer lugar.
Will Vousden
1
@ Will Vousden Correcto, es una especie de stop-gap. No es realmente DI, pero puede estar bastante cerca. Por ejemplo, ¿qué pasa si fue getInstance (supportDatabase) y la instancia devuelta se calculó en función de la base de datos que se pasó? El punto es evitar asustar a las personas con un marco DI hasta que estén listas para ello.
Bill K
320

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:

"Estoy a favor de dejar caer Singleton. Su uso es casi siempre un olor a diseño"

Otras lecturas

Si, después de lo anterior, aún necesita ayuda para decidir:

Diagrama de decisión de Singleton

Gordon
fuente
1
@ Gordon sí. E incluso si fuera posible mantener objetos entre solicitudes, Singletons aún viola un par de principios SÓLIDOS e introduce el Estado Global.
Gordon
44
Lamento ir en contra de la corriente, pero DI no es realmente una solución al problema para el que se está utilizando Singleton, a menos que esté contento con tener clases con 42 parámetros ctor (o 42 llamadas setFoo () y setBar () necesarias para hacerlo) trabajo). Sí, algunas aplicaciones, desafortunadamente, tienen que estar acopladas y dependen de muchas cosas externas. PHP es un lenguaje de pegamento, y a veces hay muchas cosas para unir.
StasM
14
@StasM si tiene 42 parámetros de ctor o necesita muchos setters, lo está haciendo mal. Mire las conversaciones de código limpio por favor. Lo siento, si no me molesto en explicar esto una vez más. No dude en preguntar en la sala de chat PHP para obtener más información.
Gordon
@ Gordon ¿Dónde está la sala de chat de php?
user658182
21

¿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.

unidad100
fuente
2
-1. Si bien estoy de acuerdo en que tener una mente abierta y flexible es un activo imprescindible para cualquier desarrollador, no redime al Singleton de ser un antipatrón. La respuesta anterior contiene tantas declaraciones inexactas y conclusiones erróneas sobre la naturaleza y los efectos del Singleton que no puedo sino desestimarlo.
Gordon
-1. Tuve que experimentar un marco con muchos singletons de primera mano y las pruebas automáticas son imposibles. Tengo que probar todo manualmente a través de prueba y error en un navegador. Algunos errores pueden prevenirse con la revisión de código (ortografía, errores de sintaxis), pero los errores funcionales a menudo están ocultos. Esta prueba requiere mucho más tiempo que las pruebas unitarias. Con las pruebas unitarias, podría decir: esta clase funciona de forma aislada, el error debe estar en otro lugar. Sin la depuración es tedioso.
Jim Martens
El marco tenía que haber incorporado el registro y el seguimiento de errores. Además, una clase que funciona correctamente aisladamente, también funcionaría correctamente en una forma única cuando se coloca en una aplicación más amplia. Lo que significa que en ese caso lo que se está rompiendo sería otra clase o función que está interactuando con ese singleton. Esto no es diferente al seguimiento de errores ordinario dentro de una aplicación grande. Lo cual es bastante difícil sin que la aplicación tenga un registro adecuado.
unity100
Incorrecto. Toneladas de singletones son definitivamente MALAS, porque crean Testing-HELL. :-) Sin embargo, una sola letra por aplicación puede ser buena. Por ejemplo: como una función de registro unificada, para implementar en todas las aplicaciones (incluidas algunas de código heredado).
Filip OvertoneSinger Rydlo
"El tiempo que puede perderse en las pruebas ..." Esta es una muy mala práctica y forma de pensar. Todas esas aplicaciones heredadas se desarrollaron con esto en mente y se hizo imposible mantenerlas, por lo que tenían que reescribirse. Si no hay pruebas, se perderá el tiempo cuando se desarrolle una nueva característica y rompa algo en alguna otra parte del sistema. El tiempo perdido en la depuración, el tiempo perdido por los usuarios que pueden utilizar esa función adecuadamente, la confianza en la aplicación perdió etc.
bogdancep
15

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.

Will Vousden
fuente
Pero Singletons puede degradarse muy suavemente en DI, las clases estáticas no pueden, lo cual es el verdadero problema con las clases estáticas.
Bill K
@Bill: Muy cierto, pero es por eso que recomendaría un enfoque DI para comenzar, en lugar de funciones sueltas o métodos estáticos :)
Will Vousden
En algunos lenguajes (como Java), las clases estáticas (o los métodos estáticos de clases) no se pueden extender. Entonces crea problemas potenciales (o, en el mejor de los casos, más trabajo) para futuros desarrolladores. Por lo tanto, algunos sugieren que los métodos estáticos generalmente deben evitarse a menos que tenga una necesidad específica de ellos.
Marvo
8

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.

Paul Sasik
fuente
1
Wow, simplemente mal. El punto central de la diferencia (la respuesta a la pregunta) es cuánto más difícil es arreglar su código para agregar una segunda instancia. Es mucho más difícil hacerlo si usaste métodos estáticos. Esto es como decir "Globals está bien en sus condiciones limitadas" cuando todo el problema con Globals es que las condiciones cambian.
Bill K
@ Bill K: estoy de acuerdo con usted y usaría un singleton si hubiera alguna complejidad. Pero estaba tratando de responder la pregunta desde el punto de vista del OP y pensé, bueno, sí, supongo que es excesivo en este caso muy limitado. Por supuesto, estaba ignorando las preocupaciones arquitectónicas o de escalabilidad y muchas otras consideraciones. ¿Debería haber incluido eso como una advertencia en mi respuesta con una explicación de por qué alguien siempre debería usar un singleton ... que ciertamente habría provocado votos negativos de los demás?
Paul Sasik
5

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):

  • Difícil de prueba unitaria
  • Problemas de inyección de dependencia
  • Puede crear problemas de bloqueo (aplicación multiproceso)

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 getInstancemétodo tradicional :

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

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.

netcoder
fuente
5

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 PDOinstancia a las personas que llaman con el getter , mientras que la de los documentos proporciona Database::singletonuna Databaseinstancia a las personas que llaman (luego usan el getter para obtener unPDO instancia).

Entonces, ¿a qué conclusión llegamos?

  • En el código de documentación, las personas que llaman obtienen una Databaseinstancia. La Databaseclase 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.
  • Si cambia su implementación para devolver otro tipo (más rico) 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:

  • Está sobreutilizado. Los programadores novatos asimilan Singleton mucho más fácilmente que asimilan otros patrones. Luego aplican su conocimiento recién descubierto en todas partes, incluso si el problema en cuestión puede resolverse mejor sin Singleton (cuando sostiene un martillo, todo parece un clavo).
  • Dependiendo del lenguaje de programación, implementar un Singleton de una manera hermética y sin fugas puede resultar una tarea titánica (especialmente si tenemos escenarios avanzados: un singleton dependiendo de otro singleton, singletons que pueden ser destruidos y recreados, etc. ) Simplemente trate de buscar la implementación Singleton "definitiva" en C ++, lo reto (soy dueño del innovador diseño Modern C ++ de Andrei Alexandrescu, que documenta gran parte del desorden).
  • Impone una carga de trabajo adicional tanto al codificar Singleton como al escribir código para acceder a él, carga de trabajo que puede prescindir siguiendo algunas restricciones autoimpuestas sobre lo que intenta hacer con las variables de su programa.

Entonces, como conclusión final: su singleton está bien. No usar Singleton está bien la mayor parte del tiempo también.

Jon
fuente
2

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.

Carreras de ligereza en órbita
fuente
2

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 gotose consideran malas prácticas.

zzzzBov
fuente
2

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.

Kell
fuente
1

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.

Hombre tonto
fuente