<h2>O que são Magic Methods em PHP?</h2>
<p>Magic Methods são métodos especiais do PHP que são invocados automaticamente quando certas ações ocorrem em um objeto. Eles começam com dois underscores (<code>__</code>) e permitem interceptar operações como leitura, escrita e chamada de métodos inexistentes. São fundamentais para criar classes flexíveis e dinâmicas, reduzindo código repetitivo e possibilitando comportamentos que seriam impossíveis de outra forma.</p>
<p>Existem mais de 15 magic methods em PHP, mas focaremos nos mais utilizados em produção. Compreendê-los é essencial para trabalhar com frameworks modernos como Laravel e Symfony, que os usam extensivamente em suas arquiteturas.</p>
<h2>Magic Methods para Propriedades: __get e __set</h2>
<p>O <code>__get()</code> é invocado quando você tenta acessar uma propriedade privada ou inexistente. O <code>__set()</code> faz o mesmo para atribuição de valores. Esses métodos são extraordinariamente úteis para criar classes com comportamento dinâmico.</p>
<pre><code class="language-php">class Usuario {
private array $dados = [];
public function __set(string $nome, mixed $valor): void {
// Intercepta atribuição: $usuario->email = 'test@example.com'
if ($nome === 'email') {
if (!filter_var($valor, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Email inválido');
}
}
$this->dados[$nome] = $valor;
}
public function __get(string $nome): mixed {
// Intercepta leitura: echo $usuario->email
if (!isset($this->dados[$nome])) {
return null;
}
return $this->dados[$nome];
}
}
$user = new Usuario();
$user->email = 'joao@example.com'; // Chama __set
$user->nome = 'João Silva'; // Chama __set
echo $user->email; // Chama __get</code></pre>
<p>Use <code>__get</code> e <code>__set</code> quando precisar de validação centralizada, logging ou comportamento dinâmico. Evite nos casos onde performance é crítica, pois há overhead em relação ao acesso direto de propriedades.</p>
<h2>Magic Methods para Métodos: __call e __callStatic</h2>
<p>O <code>__call()</code> intercepta chamadas a métodos inexistentes ou inacessíveis em instâncias. O <code>__callStatic()</code> faz o mesmo para chamadas estáticas. Esses são poderosos para criar APIs fluentes ou delegar chamadas dinamicamente.</p>
<pre><code class="language-php">class Logger {
private string $nivel = 'info';
public function __call(string $metodo, array $argumentos): void {
// Permite: $logger->debug(), $logger->error(), etc.
$niveis = ['debug', 'info', 'warning', 'error', 'critical'];
if (in_array($metodo, $niveis)) {
$this->log($metodo, $argumentos[0] ?? '');
} else {
throw new BadMethodCallException("Método $metodo não existe");
}
}
private function log(string $nivel, string $mensagem): void {
echo "[" . strtoupper($nivel) . "] " . $mensagem . "\n";
}
}
$logger = new Logger();
$logger->debug('Iniciando processamento'); // Chama __call
$logger->error('Erro crítico detectado'); // Chama __call</code></pre>
<p>Para métodos estáticos, use <code>__callStatic()</code>:</p>
<pre><code class="language-php">class BD {
public static function __callStatic(string $metodo, array $argumentos): mixed {
// Permite: BD::usuario() para chamar BD::buscar('usuario')
if (method_exists(self::class, 'buscar')) {
return self::buscar($metodo);
}
throw new BadMethodCallException("Método estático $metodo não existe");
}
private static function buscar(string $tabela): array {
return ["dados da tabela $tabela"];
}
}
$resultado = BD::usuario(); // Chama __callStatic</code></pre>
<h2>Outros Magic Methods Importantes</h2>
<p>Além de <code>__get</code>, <code>__set</code>, <code>__call</code> e <code>__callStatic</code>, existem outros métodos mágicos essenciais. O <code>__construct()</code> é invocado ao criar um objeto, enquanto <code>__toString()</code> define como o objeto é convertido para string. O <code>__isset()</code> e <code>__unset()</code> controlam verificações e destruição de propriedades dinâmicas.</p>
<pre><code class="language-php">class Produto {
private array $atributos = [];
public function __construct(string $nome, float $preco) {
$this->atributos['nome'] = $nome;
$this->atributos['preco'] = $preco;
}
public function __toString(): string {
return $this->atributos['nome'] . ' - R$ ' . $this->atributos['preco'];
}
public function __isset(string $chave): bool {
return isset($this->atributos[$chave]);
}
public function __unset(string $chave): void {
unset($this->atributos[$chave]);
}
public function __invoke(string $acao): string {
// Permite usar objeto como função: $produto('detalhes')
return "Executando: $acao no produto";
}
}
$produto = new Produto('Notebook', 3500.00);
echo $produto . "\n"; // Chama __toString
echo isset($produto->nome) . "\n"; // Chama __isset (retorna true)
echo $produto('detalhes'); // Chama __invoke</code></pre>
<p>O <code>__invoke()</code> transforma um objeto em callable, permitindo usá-lo como função. Extremamente útil em callbacks e quando você precisa de comportamentos que combinam estado com execução.</p>
<h2>Boas Práticas e Armadilhas</h2>
<p>Magic methods oferecem grande flexibilidade, mas podem prejudicar a legibilidade do código. Use-os com propósito claro: validação de dados, logging, ou padrões específicos como Active Record. Nunca os use apenas para "economizar código". Documente bem com comentários PHPDoc para que outros desenvolvedores entendam o comportamento dinâmico.</p>
<p>Evite usar magic methods de forma aninhada ou recursiva — isso causa bugs difíceis de debugar. Se performance é crítica, prefira getters e setters explícitos. Finalmente, lembre-se que IDEs terão dificuldade em autocomplete e refatoração com código dinâmico, então teste minuciosamente.</p>
<h2>Conclusão</h2>
<p>Magic methods em PHP são ferramentas poderosas quando usadas adequadamente. <code>__get</code> e <code>__set</code> centralizam validação de propriedades dinâmicas, enquanto <code>__call</code> e <code>__callStatic</code> criam APIs flexíveis. Outros como <code>__toString()</code>, <code>__isset()</code> e <code>__invoke()</code> complementam a toolkit, permitindo comportamentos que aproximam objetos de tipos primitivos. O segredo é usá-los com intenção clara, mantendo o código legível e bem documentado.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://www.php.net/manual/en/language.oop5.magic.php" target="_blank" rel="noopener noreferrer">PHP Official Documentation - Magic Methods</a></li>
<li><a href="https://phptherightway.com/#object-oriented-programming" target="_blank" rel="noopener noreferrer">PHP: The Right Way - Object-Oriented Programming</a></li>
<li><a href="https://www.oreilly.com/library/view/modern-php/9781491905173/" target="_blank" rel="noopener noreferrer">Modern PHP by Josh Lockhart - Chapter on OOP</a></li>
<li><a href="https://laravel.com/docs/eloquent" target="_blank" rel="noopener noreferrer">Laravel Documentation - Magic Methods in Eloquent</a></li>
<li><a href="https://refactoring.guru/design-patterns" target="_blank" rel="noopener noreferrer">Refactoring.guru - Magic Methods Pattern</a></li>
</ul>