Fundamentos do PHP
Escopo de variáveis e funções anônimas (closures)
Aprenda sobre escopo de variáveis e funções anônimas (closures)
Escopo de Variáveis e Funções Anônimas (Closures) em PHP
Olá! 👋 Bem-vindos à nossa aula sobre Escopo de Variáveis e Funções Anônimas (Closures) em PHP. Este é um tópico fundamental para escrever código organizado, eficiente e sem surpresas indesejadas. Compreender como o PHP gerencia a visibilidade e o tempo de vida das variáveis é crucial para qualquer desenvolvedor.
Nesta aula, vamos mergulhar nos diferentes tipos de escopo em PHP, entender como as funções anônimas funcionam e, finalmente, desvendar o poder das closures. Vamos lá! 🚀
1. Introdução ao Escopo de Variáveis
O escopo de uma variável em PHP (e na maioria das linguagens de programação) refere-se ao contexto onde essa variável pode ser acessada ou modificada. É como o "alcance" ou a "visibilidade" de uma variável dentro do seu código.
Compreender o escopo é vital para:
- Evitar conflitos de nomes: Duas variáveis com o mesmo nome podem existir em escopos diferentes sem interferir uma na outra.
- Gerenciar o ciclo de vida dos dados: Saber quando uma variável é criada e destruída.
- Escrever código modular e reutilizável: Funções devem operar com dados específicos sem afetar o resto do programa de forma inesperada.
2. Escopo de Variáveis em Detalhes
Em PHP, existem principalmente três tipos de escopo para variáveis: local, global e estático. Além disso, temos as variáveis superglobais, que são um caso especial do escopo global.
2.1. Escopo Local 🏠
Variáveis declaradas dentro de uma função têm escopo local. Isso significa que elas só podem ser acessadas de dentro daquela função. Uma vez que a função termina sua execução, essas variáveis são destruídas.
<?php
function saudacao() {
$mensagem = "Olá do escopo local!"; // Variável local
echo $mensagem . "\n";
}
saudacao();
// echo $mensagem; // Isso geraria um erro fatal: Undefined variable $mensagem
?>Explicação: A variável $mensagem só existe dentro da função saudacao(). Tentar acessá-la fora da função resultará em um erro, pois ela não está definida nesse contexto.
2.2. Escopo Global 🌍
Variáveis declaradas fora de qualquer função têm escopo global. Elas podem ser acessadas de qualquer lugar no script, exceto dentro de funções, a menos que você as declare explicitamente como globais ou use o array $GLOBALS.
Acessando Variáveis Globais dentro de Funções
Existem duas maneiras principais de acessar uma variável global de dentro de uma função:
-
Usando a palavra-chave
global: Você precisa declarar a variável comoglobaldentro da função para que ela seja reconhecida.<?php $nome = "Alice"; // Variável global function mostrarNomeGlobal() { global $nome; // Declara que estamos usando a variável global $nome echo "Dentro da função (global): " . $nome . "\n"; } mostrarNomeGlobal(); echo "Fora da função: " . $nome . "\n"; ?> -
Usando o array
$GLOBALS: O$GLOBALSé um array superglobal que contém todas as variáveis globais. Você pode acessá-las usando o nome da variável como chave do array.<?php $idade = 30; // Variável global function mostrarIdadeGlobal() { echo "Dentro da função (GLOBALS): " . $GLOBALS['idade'] . "\n"; $GLOBALS['idade'] = 31; // Você também pode modificar a variável global } echo "Idade antes: " . $idade . "\n"; mostrarIdadeGlobal(); echo "Idade depois: " . $idade . "\n"; ?>
⚠️ Cuidado: Embora seja possível, o uso excessivo de variáveis globais pode tornar o código difícil de manter e depurar, pois qualquer parte do programa pode alterá-las, levando a efeitos colaterais inesperados. Prefira passar dados para funções via argumentos sempre que possível.
2.3. Escopo Estático ⏳
Variáveis declaradas com a palavra-chave static dentro de uma função têm uma característica especial: elas mantêm seu valor entre chamadas da função, mas ainda são de escopo local (só podem ser acessadas dentro da função). Elas são inicializadas apenas na primeira vez que a função é chamada.
<?php
function contadorChamadas() {
static $contador = 0; // Variável estática, inicializada apenas uma vez
$contador++;
echo "Esta função foi chamada " . $contador . " vez(es).\n";
}
contadorChamadas(); // Saída: Esta função foi chamada 1 vez(es).
contadorChamadas(); // Saída: Esta função foi chamada 2 vez(es).
contadorChamadas(); // Saída: Esta função foi chamada 3 vez(es).
?>Explicação: Cada vez que contadorChamadas() é invocada, a variável $contador não é reinicializada para 0. Ela mantém o valor da chamada anterior.
2.4. Escopo Superglobal 🌐
As variáveis superglobais são arrays embutidos no PHP que estão sempre disponíveis em todos os escopos (global e local) sem a necessidade de usar global ou $GLOBALS.
Exemplos comuns incluem:
$_GET: Variáveis passadas via URL (query string).$_POST: Variáveis passadas via formulário HTTP POST.$_REQUEST: Uma combinação de$_GET,$_POSTe$_COOKIE.$_SESSION: Variáveis de sessão.$_COOKIE: Variáveis de cookie.$_SERVER: Informações sobre o servidor e o ambiente de execução.$_FILES: Informações sobre arquivos enviados via formulário.$_ENV: Variáveis de ambiente.
<?php
function mostrarInfoServidor() {
// Acessando uma superglobal dentro de uma função sem 'global'
echo "Nome do servidor: " . $_SERVER['SERVER_NAME'] . "\n";
}
mostrarInfoServidor();
echo "Método da requisição: " . $_SERVER['REQUEST_METHOD'] . "\n";
?>3. Funções Anônimas (Anonymous Functions)
Funções anônimas, também conhecidas como closures (embora o termo "closure" tenha um significado mais específico, como veremos), são funções sem um nome definido. Elas podem ser atribuídas a uma variável, passadas como argumento para outras funções ou retornadas por outras funções.
Elas são particularmente úteis para callbacks, onde você precisa passar uma lógica de função para outra função, mas não precisa reutilizar essa lógica em outros lugares do seu código.
3.1. Sintaxe e Uso Básico
A sintaxe de uma função anônima é semelhante à de uma função normal, mas sem o nome da função, e é seguida por um ponto e vírgula ; quando atribuída a uma variável.
<?php
// Atribuindo uma função anônima a uma variável
$saudar = function($nome) {
echo "Olá, " . $nome . "!\n";
};
$saudar("Maria"); // Chamando a função através da variável
// Passando uma função anônima como argumento (callback)
$numeros = [1, 2, 3, 4, 5];
$quadrados = array_map(function($numero) {
return $numero * $numero;
}, $numeros);
echo "Números originais: " . implode(", ", $numeros) . "\n";
echo "Números ao quadrado: " . implode(", ", $quadrados) . "\n";
// Exemplo com usort para ordenar um array de strings por comprimento
$frutas = ["maçã", "banana", "kiwi", "abacaxi"];
usort($frutas, function($a, $b) {
return strlen($a) <=> strlen($b); // Operador "spaceship" (PHP 7+)
});
echo "Frutas ordenadas por comprimento: " . implode(", ", $frutas) . "\n";
?>Explicação:
- No primeiro exemplo, a função anônima é atribuída à variável
$saudar, que então pode ser chamada como uma função regular. - No segundo e terceiro exemplos, a função anônima é passada diretamente como o segundo argumento para as funções
array_map()eusort(), respectivamente. Essas funções executam a lógica definida na função anônima para cada elemento do array.
4. Closures: Funções Anônimas com Contexto
O termo closure (fechamento) refere-se a uma função anônima que "captura" ou "fecha sobre" variáveis do escopo em que foi definida. Isso significa que a função anônima pode acessar e manipular variáveis do escopo pai, mesmo depois que o escopo pai não está mais ativo.
Para que uma função anônima possa acessar variáveis do escopo pai, você precisa usar a palavra-chave use.
4.1. Sintaxe use
A palavra-chave use é colocada após os parênteses dos parâmetros da função anônima e antes da chave de abertura {, seguida por parênteses contendo as variáveis que você deseja importar do escopo pai.
<?php
$prefixo = "Mensagem: "; // Variável do escopo pai
$imprimirMensagem = function($texto) use ($prefixo) {
echo $prefixo . $texto . "\n";
};
$imprimirMensagem("Isso é um teste."); // Saída: Mensagem: Isso é um teste.
// Outro exemplo: Criando um gerador de multiplicadores
function criarMultiplicador($fator) {
return function($numero) use ($fator) {
return $numero * $fator;
};
}
$dobrar = criarMultiplicador(2);
$triplicar = criarMultiplicador(3);
echo "Dobro de 5: " . $dobrar(5) . "\n"; // Saída: Dobro de 5: 10
echo "Triplo de 5: " . $triplicar(5) . "\n"; // Saída: Triplo de 5: 15
?>Explicação:
- No primeiro exemplo,
$imprimirMensagemé uma closure que "captura" o valor de$prefixodo escopo onde ela foi definida. - No segundo exemplo,
criarMultiplicadorretorna uma closure. Cada closure ($dobrar,$triplicar) captura um valor diferente para$fatorno momento em que é criada, e mantém esse valor mesmo depois quecriarMultiplicadorterminou sua execução.
4.2. Modificando Variáveis Externas com Closures (por Referência)
Por padrão, as variáveis importadas com use são passadas por valor para a closure. Isso significa que a closure recebe uma cópia da variável. Se você quiser que a closure modifique a variável original do escopo pai, você deve passá-la por referência usando o &.
<?php
$contador = 0;
$incrementar = function() use (&$contador) { // Passando $contador por referência
$contador++;
echo "Contador dentro da closure: " . $contador . "\n";
};
$incrementar(); // Saída: Contador dentro da closure: 1
$incrementar(); // Saída: Contador dentro da closure: 2
echo "Contador fora da closure: " . $contador . "\n"; // Saída: Contador fora da closure: 2
?>Explicação: Ao usar &$contador, a closure $incrementar agora manipula a variável $contador original, e não uma cópia.
4.3. Exemplo Oficial da Documentação PHP 📚
A documentação oficial do PHP ilustra bem o uso de use em closures.
<?php
// Exemplo adaptado da documentação oficial do PHP
// Fonte: https://www.php.net/manual/pt_BR/functions.anonymous.php
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
protected $products = [];
public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}
public function getTotal($tax)
{
$total = 0.00;
$callback = function ($quantity, $product) use ($tax, &$total) {
$pricePerItem = constant(__CLASS__ . "::PRICE_" . strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
}
$my_cart = new Cart;
// Adicionar alguns itens ao carrinho
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);
// Imprimir o total com 5% de imposto
print $my_cart->getTotal(0.05) . "\n";
// Saída esperada: 54.29
?>Explicação: Neste exemplo, a closure passada para array_walk utiliza $tax (passado por valor) para calcular o imposto e $total (passado por referência) para acumular o valor total dos produtos. Isso demonstra como closures podem encapsular variáveis de seu ambiente para realizar operações complexas.
5. Integração com Múltiplas Tecnologias
Esta aula foca exclusivamente em conceitos de PHP. Não há múltiplas tecnologias envolvidas que exijam uma seção de integração específica. Os conceitos de escopo e closures são intrínsecos ao PHP e são aplicados dentro do próprio ecossistema da linguagem.
6. Exercícios/Desafios
Como esta é uma aula teórica focada na compreensão dos conceitos, não incluiremos exercícios práticos aqui. No entanto, encorajamos você a experimentar os exemplos de código e modificá-los para solidificar seu entendimento.
7. Resumo e Próximos Passos
Parabéns! 🎉 Você concluiu a aula sobre Escopo de Variáveis e Funções Anônimas (Closures) em PHP.
Vamos recapitular os pontos principais:
- Escopo de Variáveis:
- Local: Variáveis dentro de funções, visíveis apenas ali.
- Global: Variáveis fora de funções, acessíveis dentro de funções via
globalou$GLOBALS. - Estático: Variáveis locais que mantêm seu valor entre chamadas de função.
- Superglobal: Arrays embutidos (ex:
$_GET,$_POST) disponíveis em todos os escopos.
- Funções Anônimas: Funções sem nome que podem ser atribuídas a variáveis ou passadas como callbacks.
- Closures: Funções anônimas que "capturam" variáveis do escopo em que foram definidas usando a palavra-chave
use. Elas podem ser passadas por valor ou por referência (&).
A compreensão desses conceitos é fundamental para escrever código PHP mais robusto e flexível, especialmente ao trabalhar com callbacks, APIs e frameworks modernos.
Próximos Passos: No próximo módulo, exploraremos a Programação Orientada a Objetos (POO) em PHP, onde os conceitos de escopo e encapsulamento se tornam ainda mais relevantes. Continue praticando e explorando a documentação oficial do PHP!
Até a próxima aula! 👋