php - ejemplos - tagsinput get value
¿Hay un caso de uso para singletons con acceso a la base de datos en PHP? (11)
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é fue 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::$rand))
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 ya no tengo que preocuparme por $db
.
¿Cómo puedo crear una clase singleton más pequeña, o hay un caso de uso para singletons que me falta en PHP?
Los singleton tienen muy poco uso, si no decir que no, en PHP.
En los idiomas donde los objetos viven en la memoria compartida, Singletons se puede usar para mantener el uso de memoria bajo. 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 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 instale otra . Solo cuando no tenga otra instancia, por ejemplo, cuando los gatitos mueran 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 parecer deseable, realmente no lo es, porque crea un acoplamiento al alcance global (como cualquier fenómeno global y estático). Esto hace que la Unidad de Pruebas sea más difícil y su aplicación en general menos fácil de mantener. Hay formas de mitigar esto, pero en general, si necesita tener la misma instancia en muchas clases, use Dependency Injection .
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 eliminar Singleton. Su uso es casi siempre un olor de diseño"
Otras lecturas
- ¿Cómo se está probando el patrón de registro o singleton en PHP?
- ¿Cuáles son las desventajas de usar una clase de base de datos PHP como singleton?
- Diseño de clase de abstracción de base de datos utilizando PHP PDO
- ¿Sería Singleton un buen patrón de diseño para un sitio de microblogging?
- Modificar una clase para encapsular en lugar de heredar
- ¿Cómo acceder a un objeto de otra clase?
- Por qué los Singletons no tienen uso en PHP
- The Clean Code Talks - Singletons y estado global
Si, después de lo anterior, aún necesita ayuda para decidir:
Considere simplemente cómo difiere su solución de la presentada en los documentos PHP. De hecho, solo hay una "pequeña" diferencia: su solución proporciona llamadas del comprador con una instancia de PDO
, mientras que la de los documentos proporciona llamadas de Database::singleton
de Database::singleton
con una instancia de Database
(luego usan el getter en eso para obtener una instancia de PDO
).
Entonces, ¿a qué conclusión llegamos?
- En el código de documentación, las personas que llaman obtienen una instancia de
Database
. La clase deDatabase
puede exponer (de hecho, debe exponer si tiene todos estos problemas) una interfaz más rica o de mayor nivel que el objetoPDO
que envuelve. - Si cambia su implementación para devolver otro tipo (más rico) que
PDO
, entonces las dos implementaciones son equivalentes. No se obtiene ninguna ventaja de seguir la implementación manual.
En el aspecto práctico, Singleton es un patrón bastante controvertido. Esto es principalmente porque:
- Es usado en exceso. Los programadores principiantes asimilan Singleton mucho más fácil que asimilan otros patrones. Luego continúan aplicando sus nuevos conocimientos en todas partes, incluso si el problema se puede resolver mejor sin Singleton (cuando sostiene un martillo, todo parece un clavo).
- Dependiendo del lenguaje de programación, implementar un Singleton de manera hermética y sin fugas puede ser una tarea titánica (especialmente si tenemos escenarios avanzados: un singleton dependiendo de otro singleton, singletons que se pueden destruir y recrear, etc. ) Solo intento buscar la implementación "definitiva" de Singleton en C ++, me atrevo (poseo el innovador Diseño C ++ Moderno de Andrei Alexandrescu, que documenta gran parte del lío).
- Se impone una carga de trabajo adicional tanto al codificar Singleton como al escribir código para acceder a él, la carga de trabajo que puede prescindir siguiendo unas pocas 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 en absoluto está bien la mayor parte del tiempo también.
Cuando se programa, no hay "correcto" e "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 forma que el programador no cree instantáneamente dos instancias mientras codifica borracho a medianoche.
Si tiene una clase pequeña y sencilla que no se debe instanciar más de una vez, no necesita convertirla en un singleton. Es solo una red de seguridad si lo haces.
no siempre es una mala práctica tener objetos globales. Si sabes que vas a usarlo 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 considera una mala práctica.
De acuerdo, me pregunté sobre eso por un tiempo cuando comencé mi carrera. Lo implementó de diferentes maneras y se le ocurrió dos razones para elegir no usar clases estáticas, pero son bastante grandes.
Una de ellas es que muy a menudo encontrará algo de lo que está absolutamente seguro de que nunca tendrá más de una instancia de, eventualmente tendrá un segundo. Puede terminar con un segundo monitor, una segunda base de datos, un segundo servidor, lo que sea.
Cuando esto sucede, si has usado una clase estática, te espera un refactor mucho peor que si hubieras utilizado 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, no hay otros cambios de código.
El segundo problema es probar (y honestamente, esto es lo mismo que el primer problema). Algunas veces quiere reemplazar su base de datos con una base de datos simulada. En efecto, esta es una segunda instancia del objeto de la base de datos. Esto es mucho más difícil de hacer con clases estáticas que con un singleton, solo tienes que burlar el método getInstance (), no todos los métodos en una clase estática (que en algunos idiomas puede ser muy difícil).
Realmente se trata de hábitos, y cuando las personas dicen que los "Globales" son malos, tienen muy buenas razones para decirlo, pero puede no ser siempre obvio hasta que usted mismo haya solucionado 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 en primer lugar.
En su ejemplo, se trata de una única pieza de información aparentemente invariable. 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 es necesario" por las razones que usted explicó.
PERO: no tenemos idea del tamaño y el alcance de su proyecto. Si se trata de un código simple, tal vez tirar, que probablemente no necesite cambiar, entonces sí, adelante y use miembros estáticos. Pero, si cree que su proyecto podría necesitar escalar o prepararse para la codificación de mantenimiento en el futuro, entonces, sí, es posible que desee utilizar el patrón de Singleton.
Los singletons son considerados por muchos como anti-patterns 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; generalmente es solo que una instancia es suficiente , en cuyo caso implementarlo como singleton es completamente innecesario.
Para responder a la pregunta, tienes razón en que los singletons son exagerados aquí. Una simple variable o función hará. Un enfoque mejor (más robusto), sin embargo, sería usar inyección de dependencia para eliminar la necesidad de variables globales por completo.
No te falta nada, hasta donde puedo ver. El ejemplo es bastante defectuoso. Sería una gran diferencia si la clase singleton tuviera algunas variables de instancia no estáticas.
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 sin sentido.
Primero, solo quiero decir que no encuentro muchos usos para el patrón de Singleton. ¿Por qué uno querría mantener un solo objeto a través de toda la aplicación? Especialmente para bases de datos, ¿qué pasa si quiero conectarme a otro servidor de base de datos? Tengo que desconectarme y volver a conectarme cada vez ...? De todas formas...
Existen varios inconvenientes al uso de globales en una aplicación (que es lo que hace el uso tradicional del patrón Singleton):
- Prueba difícil de unidad
- Problemas de inyección de dependencia
- Puede crear problemas de bloqueo (aplicación de subprocesos múltiples)
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 el método static getInstance
.
Puede limitar el número de instancias que puede tener una clase sin usar el método tradicional getInstance
:
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: pruebas unitarias e inyección de dependencia; sin dejar de asegurar que exista una sola instancia de la clase en su aplicación. Podría, por ejemplo, pasar el objeto resultante a sus modelos (patrón MVC) para que lo usen.
Tu interpretación es correcta Los Singleton tienen su lugar pero se usan en exceso. A menudo, el acceso a las funciones estáticas de los miembros es suficiente (en particular, cuando no necesita controlar el tiempo de construcción de ninguna manera). Mejor, puedes poner algunas funciones y variables gratuitas en un espacio de nombres.
¿Quién necesita singletons en PHP?
Tenga en cuenta que casi todas las objeciones a los singleton 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 framework / codebase, que se usarán en muchos entornos diferentes, tendrán que trabajar con frameworks / codebases diferentes previamente existentes, con la necesidad de implementar muchas solicitudes diferentes, cambiantes e incluso caprichosas de clientes / jefes. / los líderes de la gerencia / unidad lo hacen.
Ver, el patrón singleton es auto inclusivo. Cuando finalice, una clase singleton es rígida en cualquier código en el que la incluya, y actúa exactamente de la misma forma que 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 qué es un objeto singleton en cualquier punto dado de un código, incluso si el singleton se inserta en dos, tres bases de código de espagueti diferentes, antiguas e incluso espaciales. Por lo tanto, hace que sea más fácil en términos de desarrollo, incluso si hay muchas personas trabajando en ese proyecto, cuando ve un singleton siendo inicializado en un punto en cualquier base de código dado, usted sabe qué es, qué hace, cómo does, y el estado en el que se encuentra. Si fuera la clase tradicional, necesitaría hacer 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 antes con diferentes filosofías, o hecho por personas con las que no tiene contacto. (es decir, proveedor-proyecto-empresa-lo que sea que ya no exista, nada de apoyo).
- Personas que necesitan trabajar con APIs , servicios y sitios web de terceros.
Si miras 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 tienes control. Cualquier cosa puede suceder. Entonces, con una sesión única / clase de usuario, puede administrar CUALQUIER tipo de implementación de sesión / autorización de proveedores de terceros como OpenID , Facebook , Twitter y muchos más, y puede hacer TODOS al mismo tiempo desde el MISMO objeto singleton. - que es de fácil acceso, 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 para el MISMO usuario en su propio sitio web / aplicación, y hacer lo que quiera con ellos.
Por supuesto, todo esto también puede ser tonalizado con métodos tradicionales mediante el uso de clases y objetos normales: la captura aquí es que singleton es más ordenado, más ordenado y por lo tanto más manejable / comprobable en comparación con el uso tradicional de clase / objeto en tales situaciones.
- Gente que necesita hacer un desarrollo rápido
El comportamiento global de singletons hace que sea más fácil construir cualquier tipo de código con un framework que tenga una colección de singletons para construir, porque una vez que construyes bien tus clases de singleton, los métodos establecidos, maduros y establecidos estarán fácilmente disponibles y utilizable en cualquier lugar, en cualquier momento, de forma consistente. Lleva un tiempo madurar tus clases, pero después de eso, son sólidas y 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, le proporciona mucho más ahorro en el tiempo requerido para un desarrollo rápido, un método que no está usando en una instancia determinada de una aplicación se puede usar en otra integrada, y puede simplemente dar un toque a una nueva característica que el cliente / jefe / gerente de proyecto le pide solo con algunas modificaciones.
Entiendes la idea. Ahora pasemos a las objeciones a los singletons 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 las rutinas de depuración en sus singleton CON la realización de que va a depurar un singleton. Pero vea, esto no es demasiado diferente de CUALQUIER otra filosofía / método / patrón de codificación que esté disponible, simplemente es que los singleton 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: los diferentes estilos requieren diferentes enfoques.
Un punto en el que esta objeción falla es que ignora el hecho de que las razones por las que las aplicaciones se desarrollaron no son para "probar", y las pruebas no son la única fase / proceso que se aplica al desarrollo de una aplicación. Las aplicaciones están desarrolladas para uso de producción. Y como expliqué en la sección "quién necesita singletons", los singleton pueden cortar un GRAN acuerdo de la complejidad de tener que hacer que un código funcione CON e INTERMITENTE en diferentes bases de código / aplicaciones / servicios de terceros. 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é será lo próximo.
Aunque es comprensible, los programadores trabajan en circunstancias muy diferentes según su carrera. Y para las personas que trabajan en empresas relativamente grandes con departamentos definidos que atienden aplicaciones / software diferentes y definidos de forma cómoda y sin la inminente catástrofe de recortes presupuestarios / despidos y la necesidad acompañante de hacer MUCHAS cosas con muchas cosas diferentes en una moda barata / rápida / confiable, los singletons pueden no parecer tan necesarios. Y puede incluso ser una molestia / impedimento para lo que YA TIENEN.
Pero para aquellos que necesitan trabajar en las sucias trincheras del desarrollo ''ágil'', teniendo que implementar muchas solicitudes diferentes (a veces irrazonables) de su cliente / gerente / proyecto, los singletons son una salvación por las razones explicadas anteriormente.
- Otra objeción es que su huella de memoria es más alta
Debido a que existirá un singleton nuevo para cada solicitud de cada cliente, esto PUEDE ser una objeción para PHP. Con los 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 cualquier punto dado.
Sin embargo, esto es válido para CUALQUIER tipo de enfoque que pueda tomar mientras codifica cosas. Las preguntas que deben formularse son, ¿son innecesarios los métodos, los datos que son retenidos y procesados por 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. Entonces, 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.
Mira, cuando se pone de esta manera, la pregunta se vuelve completamente irrelevante: no debe haber métodos innecesarios, datos contenidos en objetos en tu código CUALQUIER forma, independientemente de si usas singletons o no. Entonces, esta objeción a los singletons se vuelve realmente graciosa en eso, ASUME que habrá métodos innecesarios, datos en los objetos creados a partir de las clases que usas.
- Algunas objeciones inválidas como ''hacen que el mantenimiento de múltiples conexiones de bases de datos sea imposible / más difícil''
No puedo ni siquiera comenzar a comprender esta objeción, cuando todo lo que uno necesita es 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 y cuando ellos son necesarios Esto puede ser tan simple como mantenerlos en matrices, aunque puedes inventar cualquier método que quieras usar para efectuar eso. Pero examinemos el caso más simple, el uso de variables y matrices en un singleton dado:
Imagine que a continuación está dentro de un singleton de base de datos determinado:
$ this -> connections = array (); (sintaxis incorrecta, acabo de tipearlo así para darle la imagen - la declaración correcta de la variable es public $ connections = array (); y su uso es $ this-> connections [''connectionkey''] naturalmente)
Puede configurar y mantener múltiples conexiones en cualquier momento en una matriz de esta manera. Y lo mismo ocurre con las consultas, los conjuntos de resultados y demás.
$ this -> query (QUERYSTRING, ''queryname'', $ this-> connections [''particulrconnection'']);
Que puede hacer una consulta a una base de datos seleccionada con una conexión seleccionada, y solo almacenar en su
$ this -> resultados
array con la clave ''queryname''. Por supuesto, necesitará tener su método de consulta codificado para esto, lo cual es trivial.
Esto le permite mantener una cantidad virtualmente infinita de (tanto como los límites de los recursos permiten por supuesto) diferentes conexiones de bases de datos y conjuntos de resultados tanto como los necesite. Y están disponibles para CUALQUIER fragmento de código en cualquier punto dado en cualquier código base en el que se haya instanciado esta clase singleton.
POR SUPUESTO, usted naturalmente necesitaría liberar los conjuntos de resultados y las conexiones cuando no los necesite, 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 conexiones / estados múltiples a aplicaciones o servicios de terceros en el mismo singleton. No tan diferente.
Para resumir, al final, los patrones de 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 singleton, también verás que las referencias a "globales" son "malas".
Reconozcámoslo: CUALQUIER cosa que no se use apropiadamente, que se abuse de ella, que se abuse de ella, ES malvada. 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 malo'', 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 particular, que generalmente termina siendo el resultado de trabajar demasiado en un estilo / método determinado, el típico conservadurismo intelectual.
Se pueden dar infinitos ejemplos de eso, que van desde "globales son malvados" hasta "los marcos son malvados". Hace alrededor de 10 años, incluso proponer el uso de un iframe en cualquier aplicación dada era una herejía. Luego viene Facebook, iframes en todas partes, y mira lo que sucedió: iframes ya no son tan malvados.
Todavía hay personas que obstinadamente insisten en que son "malvadas", y a veces también por una buena razón, pero, como puede ver, hay una necesidad, si los marcos llenan 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.