As variáveis ​​globais em PHP são consideradas práticas inadequadas? Se sim, por quê?

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

Em meus pequenos projetos PHP, geralmente vou pelo caminho processual. Geralmente, tenho uma variável que contém a configuração do sistema e, quando pretendo acessar essa variável em uma função, faço isso global $var;.

Isso é uma prática ruim?

KRTac
fonte
19
variável global é sinônimo de má prática
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
2
Experimente o teste de unidade / aceitação e você descobrirá rapidamente por que os globais são um problema: eles tornam seu código não confiável quando você faz coisas mais de uma vez.
Kzqai

Respostas:

102

Quando as pessoas falam sobre variáveis ​​globais em outras linguagens, isso significa algo diferente do que acontece em PHP. Isso porque as variáveis ​​não são realmente globais no PHP. O escopo de um programa PHP típico é uma solicitação HTTP. As variáveis ​​de sessão, na verdade, têm um escopo mais amplo do que as variáveis ​​"globais" do PHP porque geralmente abrangem muitas solicitações HTTP.

Freqüentemente (sempre?), Você pode chamar funções de membro em métodos preg_replace_callback()como este:

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

Veja callbacks para mais.

A questão é que os objetos foram fixados no PHP e, de certa forma, podem causar algum constrangimento.

Não se preocupe excessivamente em aplicar padrões ou construções de diferentes linguagens ao PHP. Outra armadilha comum é tentar transformar o PHP em uma linguagem OOP pura, colocando modelos de objetos em cima de tudo.

Como qualquer outra coisa, use variáveis ​​"globais", código procedural, uma estrutura específica e OOP porque faz sentido, resolve um problema, reduz a quantidade de código que você precisa escrever ou torna mais fácil de manter e entender, não porque você pensa você deve.

cletus
fonte
8
Deve-se notar que o PHP 5.3 resolve parte disso com funções lambda, permitindo que você evite usar a função declarada no escopo global para callbacks. +1 para conselhos de código legível
sustentável
Você não pode usar um retorno de chamada do formulário array ($obj, 'callbackMethod')em chamadas para preg_replace_callback()? (Eu sei, fui vítima dessa armadilha OOP ...)
grossvogel 01 de
25
A questão não era "as variáveis ​​globais deveriam ser usadas?". A resposta para isso seria, 'certo de vez em quando, se necessário'. A questão é se eles são más práticas. A resposta é 'sim, às vezes'. Para o projeto minúsculo de pôsteres, nada de ruim pode resultar disso - no entanto, para projetos maiores com muitos membros da equipe e muitas partes móveis, o uso intenso de variáveis ​​globais tornará o código difícil de depurar, quase impossível de refatorar e uma dor até mesmo ler. Você pode usá-los às vezes, .. claro - eles são uma merda, .. sim!
eddiemoya,
@eddiemoya Bem, disse Eddie. Existem tantas pessoas justificando práticas inadequadas, como o uso de variáveis ​​globais. Você deve evitá-los como uma praga. Qualquer diploma decente em engenharia de software vai perfurar isso em você ... os palestrantes não estão apenas dizendo o que diabos ... eles sabem por décadas de experiência. Você deve usar funções de membro sempre que possível para acessar os valores de que precisa, por exemplo get_query_var () no Wordpress etc.
27

Variáveis ​​globais, se não usadas com cuidado, podem tornar os problemas mais difíceis de encontrar. Digamos que você solicite um script php e receba um aviso dizendo que está tentando acessar um índice de um array que não existe em alguma função.

Se a matriz que você está tentando acessar é local para a função, você verifica a função para ver se cometeu um erro. Pode ser um problema com uma entrada para a função, então você verifica os locais onde a função é chamada.

Mas se esse array for global, você precisa verificar todos os lugares onde você usa essa variável global, e não só isso, você tem que descobrir em que ordem essas referências à variável global são acessadas.

Se você tiver uma variável global em um trecho de código, será difícil isolar a funcionalidade desse código. Por que você deseja isolar a funcionalidade? Portanto, você pode testá-lo e reutilizá-lo em outro lugar. Se você tem algum código que não precisa testar e não precisa reutilizar, então usar variáveis ​​globais é bom.

rojoca
fonte
Mas o erro mostra principalmente em qual arquivo / linha o script está quebrando, então ... Não vejo o problema aqui
samayo
8
Lugar onde o script quebrou! = Lugar onde o erro foi cometido.
HonoredMule
16

eu concordo com cletus. eu acrescentaria duas coisas:

  1. use um prefixo para que possa identificá-lo imediatamente como global (por exemplo, $ g_)
  2. declare-os em um local, não os espalhe por todo o código.

Atenciosamente, don

Don Dickinson
fonte
1
Sim, eu sempre prefixo variáveis ​​que pretendo usar globalmente com um sublinhado.
KRTac
9
@KRTac, mas $ _testVariable é geralmente entendido como uma variável privada - esse é um padrão informal para definir variáveis ​​privadas, não globais.
Aditya MP de
6
Uma prática comum é definir vars globais usando TODOS OS CAPS. exemplo:$DB = 'foo';
pixeline
7

Quem pode argumentar contra a experiência, diplomas universitários e engenharia de software? Eu não. Eu apenas diria que, ao desenvolver aplicativos PHP de página única orientados a objetos, me divirto mais quando sei que posso construir tudo do zero sem me preocupar com colisões de namespace. Construir do zero é algo que muitas pessoas não fazem mais. Eles têm um trabalho, um prazo, um bônus ou uma reputação com que se preocupar. Esses tipos tendem a usar tanto código pré-construído com grandes riscos que não podem arriscar usar variáveis ​​globais.

Pode ser ruim usar variáveis ​​globais, mesmo que sejam usadas apenas na área global de um programa, mas não esqueçamos daqueles que querem apenas se divertir e fazer algo funcionar .

Se isso significa usar algumas variáveis ​​(<10) no namespace global, que só são usadas na área global de um programa, que seja. Sim, sim, MVC, injeção de dependência, código externo, blá, blá, blá, blá. Mas, se você contiver 99,99% do seu código em namespaces e classes, e o código externo estiver em sandbox, o mundo não vai acabar (repito, o mundo não vai acabar) se você usar uma variável global.

Geralmente, eu não diria que usar variáveis ​​globais é uma prática ruim . Eu diria que usar variáveis ​​globais (sinalizadores e outras) fora da área global de um programa é pedir problemas e (no longo prazo) é desaconselhável porque você pode perder o controle de seus estados com bastante facilidade. Além disso, eu diria que quanto mais você aprende, menos dependente se torna das variáveis ​​globais, pois terá experimentado a "alegria" de rastrear bugs associados ao seu uso. Isso por si só o incentivará a encontrar outra maneira de resolver o mesmo problema. Coincidentemente, isso tende a empurrar as pessoas do PHP na direção de aprender como usar namespaces e classes (membros estáticos, etc ...).

O campo da ciência da computação é vasto. Se assustarmos todo mundo porque o rotulamos de ruim , eles perderão a diversão de entender verdadeiramente o raciocínio por trás do rótulo.

Use variáveis ​​globais se necessário, mas veja se consegue resolver o problema sem elas. Colisões, testes e depuração significam mais quando você entende intimamente a verdadeira natureza do problema, não apenas uma descrição do problema.

Anthony Rutledge
fonte
3

Postado novamente da Documentação Beta final do SO

Podemos ilustrar esse problema com o seguinte pseudocódigo

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

Sua primeira pergunta aqui é óbvia

De onde $bobveio?

Você está confuso? Boa. Você acabou de aprender por que os globais são confusos e considerados uma prática ruim. Se este fosse um programa real, sua próxima diversão é rastrear todas as instâncias de $bobe esperar que você encontre a correta (isso fica pior se $bobfor usado em todos os lugares). Pior, se alguém for e definir $bob(ou você esquecer e reutilizar essa variável), seu código pode quebrar (no exemplo de código acima, ter o objeto errado ou nenhum objeto causaria um erro fatal). Como praticamente todos os programas PHP usam código, include('file.php');seu trabalho, manter código como esse torna-se exponencialmente mais difícil quanto mais arquivos você adiciona.

Como podemos evitar Globais?

A melhor maneira de evitar globais é uma filosofia chamada injeção de dependência . É aqui que passamos as ferramentas de que precisamos para a função ou classe.

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

Isso é muito mais fácil de entender e manter. Não há $bobcomo saber onde foi configurado, porque o chamador é responsável por saber disso (está nos passando o que precisamos saber). Melhor ainda, podemos usar declarações de tipo para restringir o que está sendo passado. Portanto, sabemos que $bobé uma instância da Barclasse ou uma instância de um filho de Bar, o que significa que podemos usar os métodos dessa classe. Combinado com um autoloader padrão (disponível desde PHP 5.3), agora podemos rastrear onde Barestá definido. PHP 7.0 ou posterior inclui declarações de tipo expandido, onde você também pode usar tipos escalares (como intou string).

Machavity
fonte
Uma alternativa para passar $ bob em todos os lugares é tornar a classe Bar um singleton, armazenando uma instância de Bar estaticamente dentro do próprio Bar e usando um método estático para instanciar / buscar o objeto. Então, você pode $bob = Bar::instance();sempre que precisar.
Scoots de
1
Esteja ciente de que Singletons são considerados um antipadrão . A injeção de dependência evita essas armadilhas
Machavity
2
Há algum grau de contenção na postagem à qual você vinculou (por exemplo, o comentário com melhor classificação para a resposta aceita e a segunda resposta mais votada discordam totalmente da resposta aceita), o que me deixa inclinado a argumentar que o uso de Singletons deve ser considerado caso a caso, ao invés de sumariamente rejeitado.
Scoots de
0

Como:

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

é uma prática ruim (como o Wordpress $pagenow) ... hmmm

Considere isto:

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

é um erro de PHP, mas:

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

NÃO é um erro, os hypens não entrarão em conflito com variáveis ​​declaradas pelo usuário "comuns", como $pagenow. E usar MAIÚSCULAS indica uma superglobal em uso, fácil de localizar no código ou rastrear com localização em arquivos

Eu uso hífens, se tenho preguiça de construir classes de tudo para uma única solução, como:

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

Mas em casos de uso mais amplo, eu uso UM global como array:

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

O último é, para mim, uma boa prática em objetivos ou uso "cola light", em vez de desordem com classes singleton cada vez para "armazenar em cache" alguns dados. Por favor, faça um comentário se estou errado ou faltando algo estúpido aqui ...

Jonas Lundman
fonte