Como definir e usar variáveis globais? Ou porque não usá-los em tudo

25

UPDATE: Minha pergunta original foi resolvida, mas isso está se transformando em uma discussão válida sobre por que não usar variáveis globais, então estou atualizando a pergunta para refletir isso. A solução foi <?php global $category_link_prop; echo esc_url( $category_link_prop ); ?> , como sugerido por @TomJNowell.

UPDATE 2: Agora, faço exatamente o que eu queria. Mas ainda estou usando o escopo global e ficaria feliz em encontrar uma maneira melhor.

Estou tentando configurar um monte de variáveis globais para os permalinks de categorias a serem usadas em vários lugares no meu tema. A principal razão para isto é para uso tanto na navegação principal, quanto em uma série de sub-navegações que são escolhidas com base na categoria em que a postagem atual está. Este não é um tema que eu irei ser liberado para uso por outros, mas é construído para um propósito muito específico.

É assim que eu estou criando atualmente (eu colei apenas algumas das variáveis).

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' );

Agora posso fazer <?php global $prop; echo $prop; ?> nos 4 lugares que vão e recuperar o link inteiro do código. Quando isso muda, eu só preciso mudar em um só lugar. Estou aberto a alternativas que não envolvam o escopo global.

    
por JPollock 04.03.2013 / 07:23
fonte

4 respostas

21

Embora eu recomende strongmente contra isso, e isso não acelera as coisas, seu uso está incorreto.

Quando você tenta usar um global, você deve especificar a palavra-chave global primeiro. Você o especificou aqui ao definir seu valor, mas fora desse escopo ele precisa ser redeclarado como uma variável de escopo global.

por exemplo. em functions.php:

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

Em single.php, isso não funcionará:

echo $hello;

Porque $ hello é indefinido. No entanto, irá funcionar:

global $hello;
echo $hello;

Claro que você não deve fazer nada. O WordPress já tenta armazenar em cache essas coisas no cache de objetos. Você não verá nenhum aumento de velocidade ao fazer isso (você poderá ver uma pequena diminuição de velocidade), tudo o que você obterá será complexidade adicional e a necessidade de digitar muitas declarações globais que não são necessárias.

Seria melhor usar dados estruturados, como objetos ou injeção de dependência, ou, no seu caso, um conjunto de funções.

Por exemplo, aqui está um meio de fazer algo semelhante através de variáveis estáticas (ainda ruim pelas mesmas razões, mas apenas um pouquinho menos e mais fácil de digitar), por exemplo,

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

Se você realmente quiser economizar tempo armazenando dados em algum lugar para reutilizar, considere usar o sistema WP_Cache com wp_cache_get etc

    
por Tom J Nowell 04.03.2013 / 14:05
fonte
18

Não use variáveis globais , tão simples quanto isso.

Por que não usar globals

Como o uso de globals dificulta a manutenção do software a longo prazo.

  • Um global pode ser declarado em qualquer parte do código, ou em nenhum lugar, portanto não há lugar em que você possa olhar instintivamente para encontrar algum comentário sobre o que o global é usado para
  • Durante a leitura do código, você geralmente assume que as variáveis são locais para a função e não entende que a alteração de seu valor em uma função pode ter uma alteração no sistema inteiro.
  • Se eles não manipularem entrada, as funções devem retornar o mesmo valor / saída quando forem chamados com os mesmos parâmetros. O uso de globais em uma função introduz parâmetros adicionais que não são documentos na declaração da função.
  • Os globals
  • não têm nenhuma construção de inicialização específica e, portanto, você nunca pode ter certeza de quando pode acessar o valor do global e não recebe nenhum erro ao tentar acessar o global antes da inicialização.
  • Alguém mais (talvez um plug-in) pode usar globais com o mesmo nome, arruinando seu código ou arruinando-o dependendo da ordem de inicialização.

WordPress core tem muito a usar muito dos globals. Ao tentar entender como funções básicas como the_content funcionam, você de repente percebe que a variável $more não é local, mas global, e precisa pesquisar todos os arquivos principais para entender quando é definida como verdadeira.

Então, o que pode ser feito ao tentar parar de copiar e colar várias linhas de código em vez de armazenar o resultado da primeira execução em um global? Existem várias abordagens, funcionais e OOP.

A função adoçante. É simplesmente um wrapper / macro para salvar a cópia / pasta

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

Os benefícios são que agora há uma documentação para o que o antigo faz, e você tem um ponto óbvio para depuração quando o valor que está sendo retornado não é o que você espera.

Uma vez que você tenha um adoçante, é fácil armazenar o resultado em cache, se necessário (faça isso apenas se descobrir que essa função leva muito tempo para ser executada)

function notaglobal($id) {
  static $cache;

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

Isso lhe dá o mesmo comportamento global, mas com a vantagem de ter uma inicialização garantida toda vez que você acessá-lo.

Você pode ter padrões semelhantes com OOP. Eu acho que OOP geralmente não adiciona nenhum valor em plugins e temas, mas esta é uma discussão diferente

class notaglobal {
   var latestfoo2;

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

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

Este é um código mais desajeitado, mas se você tem vários valores que você gostaria de pré-calcular porque eles estão sempre sendo usados, isso pode ser um caminho a percorrer. Basicamente, este é um objeto que contém todos os seus globals de uma forma organizada. Para evitar que uma instância deste objeto seja global (você deseja usar uma instância, caso contrário, você recomputa os valores). Você pode querer usar um padrão singleton (algumas pessoas argumentam que é uma má idéia, YMMV)

Eu não gosto de acessar um atributo de objeto diretamente, então, no meu código, ele irá distorcer um pouco mais

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);
    
por Mark Kaplun 04.03.2013 / 08:09
fonte
5

Sua pergunta está envolvida com o funcionamento do PHP.

Pegue $ wpdb como exemplo

$ wpdb é uma variável global bem conhecida.

Você sabe quando será declarado e atribuído com valores?

Toda página carregada , sim, toda vez que você visita o seu site wordpress.

Da mesma forma, você precisa garantir que as variáveis que deseja globalizar sejam declaradas e atribuídas com os valores correspondentes a cada página carregada.

Embora eu não seja um designer de temas, posso dizer que o after_setup_theme é um gancho de tempo. só será acionado quando o tema for ativado.

Se eu fosse você, usaria init ou outros ganchos. Não, se eu fosse você, não usaria variáveis globais ...

Eu realmente não sou bom em explicar as coisas. Então, você deve pegar um livro se quiser se aprofundar no PHP.

    
por Jesse 04.03.2013 / 10:04
fonte
2

Você sempre pode usar um padrão singleton por meio de getters 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
    
por jgraup 25.11.2015 / 11:35
fonte