O escopo de uma variável é o contexto onde foi definida. A maioria das variáveis do PHP tem somente um único escopo. Este escopo único abrange também aqruivos inseridos por include e require. Por exemplo:
<?php
$a = 1;
include 'b.inc';
?>
Aqui a variável $a estará disponível no script incluído b.inc. Entretanto, nas funções definidas pelo usuário, um escopo de função local é introduzido. Qualquer variável utilizada dentro de uma função é, por padrão, limitada ao escopo local da função. Por exemplo:
<?php
$a = 1; /* escopo global */
function Teste()
{
echo $a; /* referência uma variável do escopo local (não definida) */
}
Teste();
?>
Este script geraá uma aviso de variável não definida de nível E_WARNING
(ou nível E_NOTICE
anteriormente ao PHP 8.0.0).
Entretanto, se a configuração INI
display_errors estiver configurada para esconder
tais diagnósticos, então nada será impresso.
Isto ocorre porque a instrução echo
refere-se a uma versão local da variável $a,
e não possui nenhum valor atribuído neste escopo. Pode-se
perceber que esta é uma pequena diferença em relação à linguagem C, em que
variáveis globais estão automaticamente disponíveis para
funções sem sobrescrever uma definição local.
Isto pode causar problemas quando inadvertidamente
modificar-se uma variável global. No PHP, as variáveis globais precisam ser
declaradas como globais dentro de uma função, se for utilizada
em uma.
global
Primeiro, um exemplo de global
:
Exemplo #1 Usando global
<?php
$a = 1;
$b = 2;
function Soma()
{
global $a, $b;
$b = $a + $b;
}
Soma();
echo $b;
?>
O script acima imprimirá 3
. Declarando
$a e $b globais na
função, fará com que todas as referências a essas variáveis referenciam a
versão global. Não há um limite para o número de variáveis
globais que podem ser manipuladas por uma função.
Uma segunda maneira de acessar variáveis do escopo global é utilizando o array especial $GLOBALS definido pelo PHP. O exemplo anterior poderia ser reescrito como:
Exemplo #2 Usando $GLOBALS no lugar de global
<?php
$a = 1;
$b = 2;
function Soma()
{
$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
}
Soma();
echo $b;
?>
O array $GLOBALS é um array associativo, sendo o nome da variável global a chave do array e o seu conteúdo da variável como o valor do elemento do array. Veja que $GLOBALS existe em qualquer escopo, isto porque $GLOBALS é uma superglobal. Segue um exemplo demonstrando o poder das superglobais:
Exemplo #3 Exemplo demonstrando superglobals e escopos
<?php
function test_superglobal()
{
echo $_POST['name'];
}
?>
Nota:
Utilizar a instrução
global
fora de uma função não é um erro. Deve ser utilizado se um arquivo for incluído dentro de uma função.
static
Outro recurso importante do escopo de variáveis é a variável static. Uma variável estática existe somente no escopo local da função, mas não perde seu valor quando o nível de execução do programa deixa o escopo. Considere o seguinte exemplo:
Exemplo #4 Exemplo demonstrando a necessidade de variáveis estáticas
<?php
function Teste()
{
$a = 0;
echo $a;
$a++;
}
?>
Essa função é inútil, já que cada vez que é chamada, define
$a com o valor 0
, e imprime
0
. A instrução $a++ , que aumenta o valor da
variável, não tem sentido já que assim que a função termina a
variável $a desaparece. Para fazer um função
contadora, que não perderá a conta atual,
a variável $a será declarada como estática:
Exemplo #5 Exemplo de uso de variáveis estáticas
<?php
function Teste()
{
static $a = 0;
echo $a;
$a++;
}
?>
Agora, a variável $a é inicializada apenas na primeira chamada da função
e cada vez que a função test()
for chamada, imprimirá o
valor de $a e depois o incrementará.
Variáveis estáticas fornecem uma solução para lidar com funções recursivas. Uma função recursiva é aquela que chama a si mesma. Cuidados devem ser tomados quando escrever funções recursivas porque é possível que ela continue na recursão indefinidamente. Deve-se assegurar que há uma maneira adequada de terminar a recursão. A seguinte função recursiva conta até 10, utilizando a variável estática $count para saber quando parar:
Exemplo #6 Variáveis estáticas em funções recursivas
<?php
function Teste()
{
static $count = 0;
$count++;
echo $count;
if ($count < 10) {
Teste();
}
$count--;
}
?>
Variáveis estáticas podem ser declaradas como visto nos exemplos acima. É possível atribuir valores a essas variáveis, que são resultados de expressões, porém não é possível usar nenhuma função, o que causará um erro de interpretação.
Exemplo #7 Declarando variáveis estáticas
<?php
function foo(){
static $int = 0; // correro
static $int = 1+2; // correto (a partir do PHP 5.6)
static $int = sqrt(121); // errado (é uma expressão)
$int++;
echo $int;
}
?>
A partir do PHP 8.1.0, quando um método com variáveis estáticas é herdado (mas não sobrescrito), o método herdado não compartilhará as variáveis estáticas do método acima. Isso significa que variáveis estáticas nos métodos agora se comportam da mesma forma que propriedades estáticas.
Exemplo #8 Uso de variáveis estáticas em métodos herdados
<?php
class Foo {
public static function counter() {
static $counter = 0;
$counter++;
return $counter;
}
}
class Bar extends Foo {}
var_dump(Foo::counter()); // int(1)
var_dump(Foo::counter()); // int(2)
var_dump(Bar::counter()); // int(3), e antes do PHP 8.1.0 int(1)
var_dump(Bar::counter()); // int(4), e antes do PHP 8.1.0 int(2)
?>
Nota:
Declarações estáticas são resolvidas em tempo de compilação.
global
e static
O PHP implementa os modificadores
static e
global
para variáveis, em termo de
referências. Por exemplo, uma variável global verdadeira,
importada dentro do escopo de uma função com a instrução global
,
na verdade, cria uma referência para a variável global. Isto pode levar a
comportamentos imprevisíveis nos seguintes casos:
<?php
function test_global_ref() {
global $obj;
$new = new stdClass;
$obj = &$new;
}
function test_global_noref() {
global $obj;
$new = new stdClass;
$obj = $new;
}
test_global_ref();
var_dump($obj);
test_global_noref();
var_dump($obj);
?>
O exemplo acima produzirá:
NULL object(stdClass)#1 (0) { }
Um comportamento similar se aplica a declaração static
.
Referências não são armazenadas estaticamente:
<?php
function &get_instance_ref() {
static $obj;
echo 'Objeto estático: ';
var_dump($obj);
if (!isset($obj)) {
$new = new stdClass;
// Assimila uma referencia a variável estática
$obj = &$new;
}
if (!isset($obj->property)) {
$obj->property = 1;
} else {
$obj->property++;
}
return $obj;
}
function &get_instance_noref() {
static $obj;
echo "Objeto estático: ";
var_dump($obj);
if (!isset($obj)) {
$new = new stdClass;
// Assimila o objeto para a variável estática
$obj = $new;
}
if (!isset($obj->property)) {
$obj->property = 1;
} else {
$obj->property++;
}
return $obj;
}
$obj1 = get_instance_ref();
$still_obj1 = get_instance_ref();
echo "\n";
$obj2 = get_instance_noref();
$still_obj2 = get_instance_noref();
?>
O exemplo acima produzirá:
Objeto estatico: NULL Objeto estatico: NULL Objeto estatico: NULL Objeto estatico: object(stdClass)#3 (1) { ["property"]=> int(1) }
Este exemplo demonstra que, atribuir uma referência a uma variável
estática, fará com que ela não se lembre quando chamou a função
&get_instance_ref()
uma segunda vez.