¿Las variables globales en PHP se consideran una mala práctica? Si es así, ¿por qué?

86
function foo () {
    global $var;
    // rest of code
}

En mis pequeños proyectos PHP, suelo seguir el camino procedimental. Generalmente tengo una variable que contiene la configuración del sistema, y ​​cuando necesito acceder a esta variable en una función, lo hago global $var;.

¿Es esta una mala práctica?

KRTac
fuente
19
variable global es sinónimo de mala práctica
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
2
Intente probarlo por unidad / aceptación y encontrará rápidamente por qué los globales son un problema: hacen que su código no sea confiable cuando hace cosas más de una vez.
Kzqai

Respuestas:

102

Cuando la gente habla de variables globales en otros lenguajes, significa algo diferente a lo que hace en PHP. Eso es porque las variables no son realmente globales en PHP. El alcance de un programa PHP típico es una solicitud HTTP. Las variables de sesión en realidad tienen un alcance más amplio que las variables "globales" de PHP porque generalmente abarcan muchas solicitudes HTTP.

A menudo (¿siempre?) Puede llamar a funciones miembro en métodos preg_replace_callback()como este:

preg_replace_callback('!pattern!', array($obj, 'method'), $str);

Consulte devoluciones de llamada para obtener más información.

El punto es que los objetos se han atornillado a PHP y de alguna manera provocan cierta incomodidad.

No se preocupe demasiado por aplicar estándares o construcciones de diferentes lenguajes a PHP. Otro error común es tratar de convertir PHP en un lenguaje puro de programación orientada a objetos colocando modelos de objetos encima de todo.

Como cualquier otra cosa, use variables "globales", código de procedimiento, un marco particular y POO porque tiene sentido, resuelve un problema, reduce la cantidad de código que necesita escribir o lo hace más fácil de mantener y de entender, no porque crea debieras.

cletus
fuente
8
Cabe señalar que PHP 5.3 aborda algo de esto con funciones lambda que le permiten evitar el uso de funciones declaradas en el alcance global para devoluciones de llamada. +1 para consejos de código legible
mantenible
¿No puede utilizar una devolución de llamada del formulario array ($obj, 'callbackMethod')en llamadas a preg_replace_callback()? (Lo sé, he caído presa de este
error de
25
La pregunta no era "¿deberían usarse alguna vez las variables globales?". La respuesta a eso sería, 'seguro en ocasiones si es necesario'. La pregunta es si son una mala práctica. La respuesta es "sí, a veces". Para el proyecto pequeño de los carteles, no puede resultar nada malo; sin embargo, para proyectos más grandes con muchos miembros del equipo y muchas partes móviles, el uso intensivo de variables globales hará que el código sea difícil de depurar, casi imposible de refactorizar y una molestia incluso leer. ¿Puedes usarlos a veces, ... seguro? ¿Kina apestan, ... sí!
eddiemoya
@eddiemoya Bien dicho Eddie. Hay tanta gente que justifica las malas prácticas como el uso de variables globales. Deberías evitarlos como a la plaga. Cualquier título decente en ingeniería de software te lo va a explicar ... los profesores no te lo están diciendo simplemente por el placer de hacerlo ... lo saben por décadas de experiencia. Debe usar funciones miembro siempre que sea posible para acceder a los valores que necesita, por ejemplo, get_query_var () en Wordpress, etc.
27

Las variables globales, si no se utilizan con cuidado, pueden hacer que los problemas sean más difíciles de encontrar. Digamos que solicita un script php y recibe una advertencia que le dice que está intentando acceder a un índice de una matriz que no existe en alguna función.

Si la matriz a la que está intentando acceder es local a la función, verifique la función para ver si ha cometido un error allí. Puede ser un problema con una entrada a la función, por lo que verifica los lugares donde se llama a la función.

Pero si esa matriz es global, debe verificar todos los lugares donde usa esa variable global, y no solo eso, debe averiguar en qué orden se accede a esas referencias a la variable global.

Si tiene una variable global en un fragmento de código, es difícil aislar la funcionalidad de ese código. ¿Por qué querrías aislar la funcionalidad? Para que pueda probarlo y reutilizarlo en otro lugar. Si tiene algún código que no necesita probar y no necesitará reutilizar, entonces usar variables globales está bien.

rojoca
fuente
Pero el error muestra principalmente en qué archivo / línea se está rompiendo el script, así que ... no veo el problema aquí
samayo
8
¡Lugar donde se rompió el script! = Lugar donde se cometió el error.
HonoredMule
16

estoy de acuerdo con cletus. agregaría dos cosas:

  1. use un prefijo para que pueda identificarlo inmediatamente como global (por ejemplo, $ g_)
  2. declararlos en un lugar, no esparcirlos por todo el código.

saludos cordiales, don

Don Dickinson
fuente
1
Jeah, siempre prefijo las variables que tengo la intención de usar globalmente con un guión bajo.
KRTac
9
@KRTac pero $ _testVariable generalmente se entiende como una variable privada, que es un estándar informal para definir variables privadas, no globales.
Aditya MP
6
Una práctica común es definir vars globales usando TODAS LAS MAYÚSCULAS. ejemplo:$DB = 'foo';
pixeline
7

¿Quién puede argumentar en contra de la experiencia, los títulos universitarios y la ingeniería de software? Yo no. Solo diría que al desarrollar aplicaciones PHP de una sola página orientadas a objetos, me divierto más cuando sé que puedo construir todo desde cero sin preocuparme por las colisiones de espacios de nombres. Construir desde cero es algo que muchas personas ya no hacen. Tienen un trabajo, una fecha límite, una bonificación o una reputación de la que preocuparse. Estos tipos tienden a usar tanto código prediseñado con mucho en juego, que no pueden arriesgarse a usar variables globales en absoluto.

Puede ser malo usar variables globales, incluso si solo se usan en el área global de un programa, pero no nos olvidemos de aquellos que solo quieren divertirse y hacer que algo funcione .

Si eso significa usar algunas variables (<10) en el espacio de nombres global, eso solo se usa en el área global de un programa, que así sea. Sí, sí, MVC, inyección de dependencia, código externo, bla, bla, bla, bla. Pero, si ha contenido el 99,99% de su código en espacios de nombres y clases, y el código externo está en un espacio aislado, el mundo no se acabará (repito, el mundo no se acabará) si utiliza una variable global.

Generalmente, no diría que usar variables globales es una mala práctica . Yo diría que usar variables globales (banderas y similares) fuera del área global de un programa es buscar problemas y (a la larga) desaconsejado porque puede perder la pista de sus estados con bastante facilidad. Además, diría que cuanto más aprenda, menos dependerá de las variables globales porque habrá experimentado la "alegría" de rastrear los errores asociados con su uso. Esto solo lo incentivará a encontrar otra forma de resolver el mismo problema. Casualmente, esto tiende a empujar a las personas de PHP en la dirección de aprender a usar los espacios de nombres y las clases (miembros estáticos, etc.).

El campo de la informática es vasto. Si asustamos a todos para que no hagan algo porque lo etiquetamos como malo , entonces pierden la diversión de comprender verdaderamente el razonamiento detrás de la etiqueta.

Use variables globales si es necesario, pero luego vea si puede resolver el problema sin ellas. Las colisiones, las pruebas y la depuración significan más cuando comprendes íntimamente la verdadera naturaleza del problema, no solo una descripción del problema.

Anthony Rutledge
fuente
3

Publicado de la versión beta de la documentación de SO finalizada

Podemos ilustrar este problema con el siguiente pseudocódigo

function foo() {
     global $bob;
     $bob->doSomething();
}

Tu primera pregunta aquí es obvia

De donde $bobsalio

¿Estas confundido? Bueno. Acaba de aprender por qué los globales son confusos y se consideran una mala práctica. Si este fuera un programa real, lo siguiente que te divertirás es buscar todas las instancias de $boby esperar que encuentres el correcto (esto empeora si $bobse usa en todas partes). Peor aún, si alguien más va y define $bob(o si olvidó y reutilizó esa variable) su código puede romperse (en el ejemplo de código anterior, tener el objeto incorrecto, o ningún objeto en absoluto, causaría un error fatal). Dado que prácticamente todos los programas PHP hacen uso de código como, include('file.php');su trabajo, mantener un código como este se vuelve exponencialmente más difícil cuanto más archivos agrega.

¿Cómo evitamos Globals?

La mejor forma de evitar los globales es una filosofía llamada Inyección de dependencia . Aquí es donde pasamos las herramientas que necesitamos a la función o clase.

function foo(\Bar $bob) {
    $bob->doSomething();
}

Esto es mucho más fácil de entender y mantener. No se puede adivinar dónde $bobse configuró porque la persona que llama es responsable de saber eso (nos está pasando lo que necesitamos saber). Mejor aún, podemos usar declaraciones de tipos para restringir lo que se pasa. Entonces sabemos que $bobes una instancia de la Barclase o una instancia de un hijo de Bar, lo que significa que sabemos que podemos usar los métodos de esa clase. Combinado con un autocargador estándar (disponible desde PHP 5.3), ahora podemos rastrear dónde Barestá definido. PHP 7.0 o posterior incluye declaraciones de tipo expandidas, donde también puede usar tipos escalares (como into string).

Machavity
fuente
Una alternativa a tener que pasar $ bob en todas partes es hacer que la clase Bar sea un singleton, almacenar una instancia de Bar de forma estática dentro de Bar y usar un método estático para instanciar / recuperar el objeto. Entonces podrá $bob = Bar::instance();hacerlo cuando lo necesite.
Scoots
1
Solo tenga en cuenta que los Singleton se consideran un anti-patrón . La inyección de dependencia evita esas trampas
Machavity
2
Existe cierto grado de contención dentro de la publicación a la que se vinculó (por ejemplo, el comentario mejor calificado a la respuesta aceptada y la segunda respuesta más votada están en total desacuerdo con la respuesta aceptada), lo que me inclina a argumentar que el uso de Singletons debería ser considerado caso por caso, en lugar de descartarlo sumariamente.
Scoots
0

Como:

global $my_global; 
$my_global = 'Transport me between functions';
Equals $GLOBALS['my_global']

es una mala práctica (como Wordpress $pagenow) ... hmmm

Considere esto:

$my-global = 'Transport me between functions';

es un error de PHP Pero:

$GLOBALS['my-global'] = 'Transport me between functions';

NO es un error, los guiones no chocarán con las variables "comunes" declaradas por el usuario, como $pagenow. Y el uso de MAYÚSCULAS indica una superglobal en uso, fácil de detectar en el código o rastrear con buscar en archivos

Uso guiones, si me da pereza construir clases de todo para una sola solución, como:

$GLOBALS['PREFIX-MY-GLOBAL'] = 'Transport me ... ';

Pero en casos de un uso más amplio, utilizo ONE global como matriz:

$GLOBALS['PREFIX-MY-GLOBAL']['context-something'] = 'Transport me ... ';
$GLOBALS['PREFIX-MY-GLOBAL']['context-something-else']['numbers'][] = 'Transport me ... ';

Esto último es para mí, una buena práctica en los objetivos o el uso de "cola light", en lugar de desordenar con clases singleton cada vez para "almacenar en caché" algunos datos. Por favor, haga un comentario si me equivoco o si me falta algo estúpido aquí ...

Jonas Lundman
fuente