PHP

Dominando Magic Methods em PHP: __get, __set, __call e Outros em Projetos Reais

7 min de leitura

Dominando Magic Methods em PHP: __get, __set, __call e Outros em Projetos Reais

O que são Magic Methods em PHP? 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 ( get() set() 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 (!filtervar($valor, FILTERVALIDATEEMAIL)) { 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 get set call() callStatic() 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 (inarray($metodo, $niveis)) { $this->log($metodo, $argumentos[0] ?? ''); }

<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-&gt;email = &#039;test@example.com&#039;

if ($nome === &#039;email&#039;) {

if (!filter_var($valor, FILTER_VALIDATE_EMAIL)) {

throw new InvalidArgumentException(&#039;Email inválido&#039;);

}

}

$this-&gt;dados[$nome] = $valor;

}

public function __get(string $nome): mixed {

// Intercepta leitura: echo $usuario-&gt;email

if (!isset($this-&gt;dados[$nome])) {

return null;

}

return $this-&gt;dados[$nome];

}

}

$user = new Usuario();

$user-&gt;email = &#039;joao@example.com&#039;; // Chama __set

$user-&gt;nome = &#039;João Silva&#039;; // Chama __set

echo $user-&gt;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 = &#039;info&#039;;

public function __call(string $metodo, array $argumentos): void {

// Permite: $logger-&gt;debug(), $logger-&gt;error(), etc.

$niveis = [&#039;debug&#039;, &#039;info&#039;, &#039;warning&#039;, &#039;error&#039;, &#039;critical&#039;];

if (in_array($metodo, $niveis)) {

$this-&gt;log($metodo, $argumentos[0] ?? &#039;&#039;);

} else {

throw new BadMethodCallException(&quot;Método $metodo não existe&quot;);

}

}

private function log(string $nivel, string $mensagem): void {

echo &quot;[&quot; . strtoupper($nivel) . &quot;] &quot; . $mensagem . &quot;\n&quot;;

}

}

$logger = new Logger();

$logger-&gt;debug(&#039;Iniciando processamento&#039;); // Chama __call

$logger-&gt;error(&#039;Erro crítico detectado&#039;); // 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(&#039;usuario&#039;)

if (method_exists(self::class, &#039;buscar&#039;)) {

return self::buscar($metodo);

}

throw new BadMethodCallException(&quot;Método estático $metodo não existe&quot;);

}

private static function buscar(string $tabela): array {

return [&quot;dados da tabela $tabela&quot;];

}

}

$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-&gt;atributos[&#039;nome&#039;] = $nome;

$this-&gt;atributos[&#039;preco&#039;] = $preco;

}

public function __toString(): string {

return $this-&gt;atributos[&#039;nome&#039;] . &#039; - R$ &#039; . $this-&gt;atributos[&#039;preco&#039;];

}

public function __isset(string $chave): bool {

return isset($this-&gt;atributos[$chave]);

}

public function __unset(string $chave): void {

unset($this-&gt;atributos[$chave]);

}

public function __invoke(string $acao): string {

// Permite usar objeto como função: $produto(&#039;detalhes&#039;)

return &quot;Executando: $acao no produto&quot;;

}

}

$produto = new Produto(&#039;Notebook&#039;, 3500.00);

echo $produto . &quot;\n&quot;; // Chama __toString

echo isset($produto-&gt;nome) . &quot;\n&quot;; // Chama __isset (retorna true)

echo $produto(&#039;detalhes&#039;); // 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 &quot;economizar código&quot;. 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>

Comentários

Mais em PHP

Camada Controller: Recebendo Requisições e Orquestrando Respostas na Prática
Camada Controller: Recebendo Requisições e Orquestrando Respostas na Prática

O Papel do Controller na Arquitetura MVC O controller é o intermediário funda...

Dominando Transações em PDO: Garantindo Integridade dos Dados em Projetos Reais
Dominando Transações em PDO: Garantindo Integridade dos Dados em Projetos Reais

O que são Transações em PDO? Uma transação é um conjunto de operações no banc...

Como Usar Prepared Statements e Prevenção de SQL Injection em Produção
Como Usar Prepared Statements e Prevenção de SQL Injection em Produção

O Problema: SQL Injection SQL Injection é uma das vulnerabilidades mais críti...