PHP es mi primer lenguaje de programación. No puedo entender cuándo usar clases estáticas frente a objetos instanciados.
Me doy cuenta de que puedes duplicar y clonar objetos. Sin embargo, en todo mi tiempo usando php, cualquier objeto o función siempre terminaba como un solo valor de retorno (matriz, cadena, int) o vacío.
Entiendo conceptos en libros como una clase de personaje de videojuego. duplicar el objeto del automóvil y hacer que el nuevo sea rojo , todo tiene sentido, pero lo que no es su aplicación en php y aplicaciones web.
Un simple ejemplo. Un blog. ¿Qué objetos de un blog se implementarían mejor como objetos estáticos o instanciados? La clase DB? ¿Por qué no simplemente instanciar el objeto db en el ámbito global? ¿Por qué no hacer cada objeto estático en su lugar? ¿Qué pasa con el rendimiento?
¿Es todo solo estilo? ¿Hay una manera adecuada de hacer esto?
Las dos razones principales contra el uso de métodos estáticos son:
Tener una llamada a un método estático dentro de otro método es en realidad peor que importar una variable global. En PHP, las clases son símbolos globales, por lo que cada vez que llama a un método estático se basa en un símbolo global (el nombre de la clase). Este es un caso cuando global es malvado. Tuve problemas con este tipo de enfoque con algún componente de Zend Framework. Hay clases que usan llamadas a métodos estáticos (fábricas) para construir objetos. Fue imposible para mí suministrar otra fábrica a esa instancia para obtener un objeto personalizado devuelto. La solución a este problema es utilizar solo instancias y métodos de instancias y aplicar singletons y similares al comienzo del programa.
Miško Hevery , que trabaja como entrenador ágil en Google, tiene una teoría interesante, o más bien aconseja, que separemos el tiempo de creación del objeto del momento en que lo usamos. Entonces el ciclo de vida de un programa se divide en dos. La primera parte (
main()
digamos el método), que se encarga de todo el cableado de objetos en su aplicación y la parte que hace el trabajo real.Entonces, en lugar de tener:
Más bien deberíamos hacer:
Y luego, en la página índice / principal, lo haríamos (este es el paso de cableado del objeto, o el momento de crear el gráfico de instancias que utilizará el programa):
La idea principal es desacoplar las dependencias de tus clases. De esta forma, el código es mucho más extensible y, lo más importante para mí, comprobable. ¿Por qué es más importante ser comprobable? Debido a que no siempre escribo el código de la biblioteca, la extensibilidad no es tan importante, pero la comprobabilidad es importante cuando refactorizo. De todos modos, el código comprobable generalmente produce código extensible, por lo que no es realmente una situación de uno u otro.
Miško Hevery también hace una clara distinción entre singletons y Singletons (con o sin S mayúscula). La diferencia es muy simple. Los singletons con minúscula "s" se aplican mediante el cableado en el índice / principal. Instancia un objeto de una clase que no implementa el patrón Singleton y se asegura de pasar esa instancia a cualquier otra instancia que lo necesite. Por otro lado, Singleton, con una "S" mayúscula es una implementación del patrón clásico (anti). Básicamente, un disfraz global que no tiene mucho uso en el mundo PHP. No he visto uno hasta este punto. Si desea que todas sus clases utilicen una única conexión de base de datos, es mejor hacerlo así:
Al hacer lo anterior, está claro que tenemos un singleton y también tenemos una buena manera de inyectar un simulacro o un trozo en nuestras pruebas. Es sorprendente cómo las pruebas unitarias conducen a un mejor diseño. Pero tiene mucho sentido cuando crees que las pruebas te obligan a pensar en la forma en que usarías ese código.
La única situación en la que usaría (y los he usado para imitar el objeto prototipo de JavaScript en PHP 5.3) miembros estáticos es cuando sé que el campo respectivo tendrá el mismo valor de instancia cruzada. En ese punto, puede usar una propiedad estática y quizás un par de métodos getter / setter estáticos. De todos modos, no olvide agregar la posibilidad de anular el miembro estático con un miembro de instancia. Por ejemplo, Zend Framework estaba usando una propiedad estática para especificar el nombre de la clase de adaptador DB utilizada en instancias de
Zend_Db_Table
. Ha pasado un tiempo desde que los he usado, por lo que puede que ya no sea relevante, pero así es como lo recuerdo.Los métodos estáticos que no tratan con propiedades estáticas deberían ser funciones. PHP tiene funciones y deberíamos usarlas.
fuente
Entonces, en PHP, la estática se puede aplicar a funciones o variables. Las variables no estáticas están vinculadas a una instancia específica de una clase. Los métodos no estáticos actúan en una instancia de una clase. Así que inventemos una clase llamada
BlogPost
.title
Sería un miembro no estático. Contiene el título de esa publicación de blog. También podríamos tener un método llamadofind_related()
. No es estático porque requiere información de una instancia específica de la clase de publicación de blog.Esta clase se vería así:
Por otro lado, usando funciones estáticas, puede escribir una clase como esta:
En este caso, dado que la función es estática y no actúa en ninguna publicación de blog en particular, debe pasarla como argumento.
Fundamentalmente, esta es una pregunta sobre el diseño orientado a objetos. Sus clases son los sustantivos en su sistema, y las funciones que actúan sobre ellos son los verbos. Las funciones estáticas son de procedimiento. Usted pasa el objeto de las funciones como argumentos.
Actualización: También agregaría que la decisión rara vez es entre métodos de instancia y métodos estáticos, y más entre usar clases y usar matrices asociativas. Por ejemplo, en una aplicación de blogs, puede leer publicaciones de blog de la base de datos y convertirlas en objetos, o dejarlas en el conjunto de resultados y tratarlas como matrices asociativas. Luego, escribe funciones que toman matrices asociativas o listas de matrices asociativas como argumentos.
En el escenario OO, escribe métodos en su
BlogPost
clase que actúan en publicaciones individuales, y escribe métodos estáticos que actúan en colecciones de publicaciones.fuente
Un largo camino, sí. Puede escribir programas orientados a objetos perfectamente buenos sin usar miembros estáticos. De hecho, algunas personas argumentarían que los miembros estáticos son una impureza en primer lugar. Sugeriría que, como principiante en oop, intente evitar miembros estáticos por completo. Te obligará a escribir en un objeto orientado en lugar de un estilo de procedimiento .
fuente
Tengo un enfoque diferente para la mayoría de las respuestas aquí, especialmente cuando uso PHP. Creo que todas las clases deberían ser estáticas a menos que tenga una buena razón por la que no. Algunas de las razones del "por qué no" son:
Déjame tomar un ejemplo. Como cada script PHP produce código HTML, mi framework tiene una clase de escritor html. Esto garantiza que ninguna otra clase intentará escribir HTML, ya que es una tarea especializada que debe concentrarse en una sola clase.
Por lo general, usaría la clase html de esta manera:
Cada vez que se llama a get_buffer (), restablece todo para que la próxima clase que use el escritor html comience en un estado conocido.
Todas mis clases estáticas tienen una función init () que debe llamarse antes de que la clase se use por primera vez. Esto es más por convención que una necesidad.
La alternativa a una clase estática en este caso es desordenada. No querrá que cada clase que necesita escribir un poco de html tenga que administrar una instancia del escritor html.
Ahora te daré un ejemplo de cuándo no usar clases estáticas. Mi clase de formulario administra una lista de elementos de formulario como entradas de texto, listas desplegables y más. Por lo general, se usa así:
No hay forma de que pueda hacer esto con clases estáticas, especialmente teniendo en cuenta que algunos de los constructores de cada clase agregada hacen mucho trabajo. Además, la cadena de herencia para todos los elementos es bastante compleja. Así que este es un claro ejemplo donde las clases estáticas no deberían usarse.
La mayoría de las clases de utilidad, como las cadenas de conversión / formateo, son buenas candidatas para ser una clase estática. Mi regla es simple: todo se vuelve estático en PHP a menos que haya una razón por la cual no debería.
fuente
"Tener una llamada a un método estático dentro de otro método es realmente peor que importar una variable global". (defina "peor") ... y "Los métodos estáticos que no tratan con propiedades estáticas deberían ser funciones".
Ambas son declaraciones bastante amplias. Si tengo un conjunto de funciones relacionadas con el tema, pero los datos de la instancia son totalmente inapropiados, preferiría tenerlos definidos en una clase y no cada uno de ellos en el espacio de nombres global. Solo estoy usando la mecánica disponible en PHP5 para
Es una forma conveniente de forzar una mayor cohesión y un menor acoplamiento.
Y FWIW: no existe tal cosa, al menos en PHP5, como "clases estáticas"; Los métodos y propiedades pueden ser estáticos. Para evitar la creación de instancias de la clase, también se puede declarar abstracta.
fuente
Primero pregúntese, ¿qué va a representar este objeto? Una instancia de objeto es buena para operar en conjuntos separados de datos dinámicos.
Un buen ejemplo sería ORM o capa de abstracción de base de datos. Puede tener múltiples conexiones de base de datos.
Esas dos conexiones ahora pueden operar de forma independiente:
Ahora dentro de este paquete / biblioteca, puede haber otras clases como Db_Row, etc. para representar una fila específica devuelta desde una instrucción SELECT. Si esta clase Db_Row fuera una clase estática, supondría que solo tiene una fila de datos en una base de datos y sería imposible hacer lo que podría hacer una instancia de objeto. Con una instancia, ahora puede tener un número ilimitado de filas en un número ilimitado de tablas en un número ilimitado de bases de datos. El único límite es el hardware del servidor;).
Por ejemplo, si el método getRows en el objeto Db devuelve una matriz de objetos Db_Row, ahora puede operar en cada fila independientemente uno del otro:
Un buen ejemplo de una clase estática sería algo que maneje variables de registro o variables de sesión, ya que solo habrá un registro o una sesión por usuario.
En una parte de su solicitud:
Y en otra parte:
Dado que solo habrá un usuario a la vez por sesión, no tiene sentido crear una instancia para la sesión.
Espero que esto ayude, junto con las otras respuestas para ayudar a aclarar las cosas. Como nota al margen, verifique " cohesión " y " acoplamiento ". Esbozan algunas muy, muy buenas prácticas para usar al escribir su código que se aplican a todos los lenguajes de programación.
fuente
Si su clase es estática, eso significa que no puede pasar su objeto a otras clases (ya que no hay una instancia posible), lo que significa que todas sus clases usarán directamente esa clase estática, lo que significa que su código ahora está estrechamente unido a la clase .
El acoplamiento estricto hace que su código sea menos reutilizable, frágil y propenso a errores. Desea evitar las clases estáticas para poder pasar la instancia de la clase a otras clases.
Y sí, esta es solo una de las muchas otras razones, algunas de las cuales ya se han mencionado.
fuente
En general, debe usar variables miembro y funciones miembro a menos que sea absolutamente necesario compartirlas entre todas las instancias o a menos que esté creando un singleton. El uso de datos de miembros y funciones de miembros le permite reutilizar sus funciones para múltiples datos diferentes, mientras que solo puede tener una copia de los datos en los que opera si usa datos y funciones estáticos. Además, aunque no es aplicable a PHP, las funciones estáticas y los datos hacen que el código no sea reentrante, mientras que los datos de clase facilitan la reentrada.
fuente
Me gustaría decir que definitivamente hay un caso en el que me gustaría tener variables estáticas en aplicaciones en varios idiomas. Podría tener una clase a la que le pase un idioma (por ejemplo, $ _SESSION ['idioma']) y, a su vez, accederá a otras clases diseñadas de la siguiente manera:
Usar Strings :: getString ("somestring") es una buena manera de abstraer el uso del idioma de su aplicación. Puede hacerlo como quiera, pero en este caso, tener cada archivo de cadenas con constantes con valores de cadena a los que acceda la clase Cuerdas funciona bastante bien.
fuente