¿Cómo establecer y usar variables globales? ¿O por qué no usarlos en absoluto?

25

ACTUALIZACIÓN: Mi pregunta original se ha resuelto, pero esto se está convirtiendo en una discusión válida sobre por qué no usar variables globales, por lo que estoy actualizando la pregunta para reflejar eso. La solución fue <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?> como sugirió @TomJNowell.

ACTUALIZACIÓN 2: Ahora tengo que hacer exactamente lo que quería. Pero sigo usando el alcance global y me encantaría encontrar una mejor manera.

Estoy tratando de configurar un montón de variables globales para los enlaces permanentes a las categorías que se utilizarán en varios lugares de mi tema. La razón principal de esto es para su uso tanto en la navegación principal como en una serie de subnavegaciones que se eligen según la categoría en la que se encuentra la publicación actual. Este no es un tema. se lanzará para el uso de otros, pero está diseñado para un propósito muy específico.

Así es como los estoy creando actualmente (solo he pegado algunas de las variables).

function set_global_nav_var()
{
    //proposal
    global $prop;
    // Get the ID of a given category
    $category_id_prop = get_cat_ID( 'proposal' );
    // Get the URL of this category
    $category_link_prop = get_category_link( $category_id_prop );
    $prop = '<a href="' .esc_url( $category_link_prop ). '" title="Proposal">Proposal</a>';

    //Calvinball
    global $cb;
    // Get the ID of a given category
    $category_id_cb = get_cat_ID( 'calvinball' );
    // Get the URL of this category
    $category_link_cb = get_category_link( $category_id_cb );
    $cb = '<a href="' .esc_url( $category_link_cb). '" title="Calvinball">Calvinball</a>';
}
add_action( 'init', 'set_global_nav_var' );

Ahora puedo hacer <?php global $prop; echo $prop; ?> int he 4 lugares que van y recuperar todo el enlace para el código. Cuando eso cambie solo necesito cambiarlo en un lugar. Estoy abierto a alternativas que no involucren el alcance global.

    
pregunta JPollock 04.03.2013 - 07:23

4 respuestas

21

Aunque desaconsejo esto enérgicamente, y no acelerará las cosas, su uso es incorrecto.

Cuando intenta utilizar un global, primero debe especificar la palabra clave global. Lo ha especificado aquí cuando define su valor, pero fuera de ese ámbito debe ser redeclarado como una variable de alcance global.

por ejemplo en functions.php:

function test() {
    global $hello;
    $hello = 'hello world';
}
add_action( 'after_theme_setup', 'test' );

En single.php, esto no funcionará:

echo $hello;

Porque $ hola no está definido. Sin embargo, esto funcionará :

global $hello;
echo $hello;

Por supuesto que no debes hacer nada. WordPress ya intenta almacenar estas cosas en la caché de objetos. No verá ningún aumento en la velocidad por hacer esto (puede ver una pequeña disminución de la velocidad), todo lo que obtendrá será una complejidad adicional y la necesidad de escribir muchas declaraciones globales que no son necesarias.

Le convendría utilizar datos estructurados, como objetos o inyección de dependencia, o en su caso, un conjunto de funciones.

Por ejemplo, aquí hay un medio para hacer algo similar a través de variables estáticas (aún así es malo por las mismas razones, pero solo un poco menos, y más fácil de escribir), por ejemplo,

function awful_function( $new_hello='' ) {
    static $hello;
    if ( !empty( $new_hello ) ) {
        $hello = $new_hello;
    }
    return $hello;
}

awful_function( 'telephone' );
echo awful_function(); // prints telephone
awful_function( 'banana');
echo awful_function(); // prints banana

Si realmente desea ahorrar tiempo almacenando datos en algún lugar para reutilizarlos, considere usar el sistema WP_Cache con wp_cache_get etc.

    
respondido por el Tom J Nowell 04.03.2013 - 14:05
18

No uses variables globales , tan simple como eso.

Por qué no usar globales

Debido a que el uso de globales hace que sea más difícil mantener el software a largo plazo.

  • Un global puede ser declarado en cualquier parte del código, o en ninguna parte, por lo tanto, no hay un lugar en el que pueda buscar instintivamente para encontrar algún comentario sobre para qué se usa el global
  • Mientras lee el código, generalmente asume que las variables son locales a la función y no entiende que cambiar su valor en una función puede tener un cambio en todo el sistema.
  • Si no manejan la entrada, las funciones deben devolver el mismo valor / salida cuando se llaman con los mismos parámetros. El uso de elementos globales en una función introduce parámetros adicionales que no están documentados en la declaración de la función.
  • los globales no tienen ninguna construcción de inicialización específica y, por lo tanto, nunca puede estar seguro de cuándo puede acceder al valor del global, y no recibe ningún error al intentar acceder al global antes de la inicialización.
  • Alguien más (quizás un complemento) puede usar globales con el mismo nombre, arruinando tu código, o arruinarlo dependiendo de la orden de inicialización.

El núcleo de WordPress tiene mucho que ver con el uso de los globales. Al tratar de comprender cómo funcionan las funciones básicas como the_content , de repente te das cuenta de que la variable $more no es local sino global y necesitas buscar en todos los archivos principales para entender cuándo se establece en verdadero.

Entonces, ¿qué se puede hacer cuando se intenta detener la copia y pegar varias líneas de código en lugar de almacenar el primer resultado de ejecución en forma global? Hay varios enfoques, funcionales y OOP.

La función edulcorante. Es simplemente una envoltura / macro para guardar la copia / pegar

// input: $id - the category id
// returns: the foo2 value of the category
function notaglobal($id) {
  $a = foo1($id);
  $b = foo2($a);
  return $b;
}

Los beneficios son que ahora hay una documentación de lo que hace el anterior global, y tiene un punto obvio para la depuración cuando el valor que se devuelve no es el que espera.

Una vez que tenga un edulcorante, es fácil almacenar en caché el resultado si es necesario (hágalo solo si descubre que esta función tarda mucho tiempo en ejecutarse)

function notaglobal($id) {
  static $cache;

  if (!isset($cache)) {
    $a = foo1($id);
    $b = foo2($a);
    $cache = $b;
  } 
  return $cache;
} 

Esto le da el mismo comportamiento que un global pero con la ventaja de tener una inicialización segura cada vez que accede a él.

Puedes tener patrones similares con OOP. Encuentro que la POO generalmente no agrega ningún valor a los complementos y temas, pero esta es una discusión diferente

class notaglobal {
   var latestfoo2;

   __constructor($id) {
     $a = foo1($id);
     $this->latestfoo2 = foo2($a)
   }
}

$v = new notaglobal($cat_id);
echo $v->latestfoo2;

Este es un código más torpe, pero si tiene varios valores que le gustaría calcular previamente porque siempre se están usando, esta puede ser una manera de hacerlo. Básicamente, este es un objeto que contiene todos sus globales de una manera organizada. Para evitar que una instancia de este objeto se convierta en global (si lo desea, en una instancia, de lo contrario, vuelva a calcular los valores) es posible que desee utilizar un patrón de singleton (algunas personas sostienen que es una mala idea, YMMV)

No me gusta acceder a un atributo de objeto directamente, por lo que en mi código se combará un poco más

class notaglobal {
   var latestfoo2;

   __constructor() {}

   foo2($id) {  
     if (!isset($this->latestfoo2)) {    
       $a = foo1($id);
       $b = foo2($a);
       $this->latestfoo2= $b;
     } 
     return $this->latestfoo2;
   }
}

$v = new notaglobal();
echo $v->foo2($cat_id);
    
respondido por el Mark Kaplun 04.03.2013 - 08:09
5

Su pregunta está relacionada con cómo funciona php.

Tome $ wpdb como ejemplo

$ wpdb es una variable global conocida.

¿Sabe cuándo se declarará y se le asignarán valores?

Cada página cargada , sí, cada vez que visita su sitio de wordpress.

Del mismo modo, debe asegurarse de que las variables que desea globalizar se declararán y asignarán con los valores correspondientes en cada página cargada.

Aunque no soy un diseñador de temas, puedo decir que after_setup_theme es un gancho de tiempo. solo se activará cuando se active el tema.

Si yo fuera tú, usaré init u otros ganchos. No, si yo fuera tú, no usaré variables globales en absoluto ...

Realmente no soy bueno explicando cosas. Por lo tanto, debe recoger un libro si desea profundizar en PHP.

    
respondido por el Jesse 04.03.2013 - 10:04
2

Siempre puedes usar un patrón de singleton a través de captadores estáticos.

<ul>
    <li><?php echo MyGlobals::get_nav_prop( 'proposal' )[ 'html' ]; ?></li>
    <li><?php echo MyGlobals::get_nav_prop( 'calvinball', 'html' ); ?></li>
</ul>


<?php

if ( ! class_exists('MyGlobals') ):

class MyGlobals {

    public $props;

    public function __construct(){
      $this->props = array (
        'proposal' => array( 'title' => 'Proposal', 'text' => 'Proposal' ),
        'calvinball' => array( 'title' => 'Calvinball', 'text' => 'Calvinball' ),
      );
    }

    public function get_nav_prop ( $term, $prop = false )
    {
      $o = self::instance();
      if ( ! isset( $o->props[$term] ) ) {  return falst; }
      if ( ! isset( $o->props[$term][ 'html' ] ) ) {
          $id = get_cat_ID( $term );
          $link = esc_url ( get_category_link( $id ) );
          $title = $o->props[$term]['title'];
          $text = $o->props[$term]['text'];
          $o->props[$term]['html'] = '<a href="'.$link.'" title="'.$title.'">'.$text.'</a>';
          $o->props[$term]['link'] = $link;
          $o->props[$term]['id'] = $id;
      }

      if($prop){ return isset($o->props[$term][$prop]) ? $o->props[$term][$prop] : null; }

      return $o->props[$term];
    }

    // -------------------------------------

    private static $_instance;

    public static function instance(){

      if(!isset(self::$_instance)) {
        self::$_instance = new MyGlobals();
      }
      return self::$_instance;
    }

}

endif; // end MyGlobals
    
respondido por el jgraup 25.11.2015 - 11:35

Lea otras preguntas en las etiquetas