Métodos Mágicos PHP

Métodos mágicos no PHP são métodos que são chamados automaticamente dependendo do que for feito com um objeto de uma classe. Mas como assim dependendo do que foi feito com um objeto de uma classe? Por exemplo, o método __construct de uma classe, muito conhecido e utilizado, ele é um método mágico, você não precisa chamá-lo, ele é será chamado automaticamente quando uma classe for instanciada. Mas ele não é o único método mágico existente no PHP, existem vários outros. A seguir veremos todos os métodos mágicos do PHP e um exemplo de uso de cada um.

Métodos Mágicos

Conforme já mencionado, métodos mágicos são métodos que são chamados automaticamente dependendo do que for feito com um objeto de uma classe. Escrevi um artigo sobre constantes mágicas no PHP, que é semelhante aos métodos mágicos, não deixe de dar uma olhada Constante Mágicas PHP. Voltando aos métodos mágicos, eles são identificados por iniciarem com dois underlines antes do nome, por exemplo, __construct, __destruct, __get, __set, essas palavras são reservadas pelo PHP, por tanto, cuidado ao usar fora do contexto de classes. Além disso, métodos mágicos devem ser públicos para evitar possíveis erros de encapsulamento. Veja uma lista de todos os métodos mágicos do PHP

  • __construct()
  • __destruct()
  • __call()
  • __callStatic()
  • __get()
  • __set()
  • __isset()
  • __unset()
  • __sleep()
  • __wakeup()
  • __serialize()
  • __unserialize()
  • __toString()
  • __invoke()
  • __set_state()
  • __clone()
  • __debugInfo()

__construct()

Esse método é chamado quando criamos um objeto de uma classe, ou seja, quando a classe é instanciada.


class Pessoa
{
    public function __construct()
    {
        echo "Objeto instanciado";
    }
}

$pessoa = new Pessoa();

// Resultado: Objeto instanciado

__destruct()

Na tradução livre, destrutor, ele é chamado quando um objeto é removido, destruído, ou o script PHP chegou ao fim da execução. Mesmo que o script tenha um exit ele será chamado da mesma forma.


class Pessoa
{
    public function __destruct()
    {
        echo "Destrutor chamado";
    }
}

$pessoa = new Pessoa();
$pessoa = null;

// Resultado: Destrutor chamado

No exemplo acima o método __destruct será executado no momento que o objeto pessoa foi removido, quando foi definindo o valor null para ele. Mas caso não seja definido um valor null para ele, o destrutor será executado após o fim do script, conforme exemplo abaixo:


class Pessoa
{
    public function __destruct()
    {
        echo "Destrutor chamado";
    }
}

$pessoa = new Pessoa();

$nome = "Pedro ";
echo $nome;

// Resultado: Pedro Destrutor chamado

__call()

É chamado quando tentamos usar um método que não existe na classe ou o método está inacessível. O método mágico __call recebe dois parâmetros obrigatórios, que são os seguintes:

$name Nome do método que foi invocado.
$arguments Array com os valores dos parâmetros passado no método.

class Pessoa
{
    public function __call($name, $arguments)
    {
        echo "Você invocou o método '$name' com os parâmetros com os valores " . implode(', ', $arguments);
    }
}

$pessoa = new Pessoa();
$pessoa->andar("devagar");

// Resultado: Você invocou o método 'andar' com os parâmetros com os valores devagar

__callStatic()

Idêntico ao método __call, a diferença é que ele é chamado para métodos static. O método mágico __callStatic recebe dois parâmetros obrigatórios, que são os seguintes:

$name Nome do método que foi invocado.
$arguments Array com os valores dos parâmetros passados no método.

class Pessoa
{
    public static function __callStatic($name, $arguments)
    {
        echo "Você invocou o método '$name' com os parâmetros com os valores " . implode(', ', $arguments);
    }
}

Pessoa::andar("devagar");

// Resultado: Você invocou o método 'andar' com os parâmetros com os valores devagar

__get()

Esse método mágico é chamado quando tentamos usar uma propriedade que não foi definida na classe ou a propriedade está inacessível, é obrigatório definir o parâmetro $name, veja um exemplo:

$name Nome da propriedade que foi tentado usar.

class Pessoa
{
    public function __get($name)
    {
        echo "A propriedade " . $name . " não existe";
    }
}

$pessoa = new Pessoa();
echo $pessoa->altura;

// Resultado: A propriedade altura não existe

__set()

Esse método mágico é chamado quando tentamos definir um valor para uma propriedade que não existe ou a propriedade está inacessível, ele pode ser útil para evitar possíveis erros quando uma propriedade é setada sem ela existir, podendo validar para retornar uma mensagem de erro ou até mesmo criar a propriedade, é obrigatório definir os parâmetros $name e $value, veja um exemplo:

$name Nome da propriedade que foi tentado setar um valor.
$value Valor setado na propriedade.

class Pessoa
{
    public function __set($name, $value)
    {
        // Cria a propriedade definindo o valor que foi setado para ela
        $this->$name = $value;

        echo "Você setou a propriedade " . $name . " com o valor " . $value;
    }
}

$pessoa = new Pessoa();
$pessoa->altura = "1,80";

// Resultado: Você setou a propriedade altura com o valor 1,80

__isset()

É chamado quando tentamos verificar com a função isset uma propriedade que não foi definida na classe ou a propriedade está inacessível, é obrigatório definir o parâmetro $name, veja um exemplo:

$name Nome da propriedade que foi tentado verificar se existe.

class Pessoa
{
    public function __isset($name)
    {
        echo "Você tentou verificar se existe a propriedade " . $name . " que não foi definida na classe";
    }
}

$pessoa = new Pessoa();

if (isset($pessoa->altura)) {
    
}

// Resultado: Você tentou verificar se existe a propriedade altura que não foi definida na classe

__unset()

É chamado quando tentamos destruir com a função unset uma propriedade que não foi definida na classe ou a propriedade está inacessível, é obrigatório definir o parâmetro $name, veja um exemplo:

$name Nome da propriedade que foi tentado destruir.

class Pessoa
{
    public function __unset($name)
    {
        echo "Você tentou destruir o parâmetro " . $name . " que não foi definida na classe";
    }
}

$pessoa = new Pessoa();

unset($pessoa->altura);

// Resultado: Você tentou destruir o parâmetro altura que não foi definida na classe

__sleep()

É chamado quando tentamos serializar um objeto utilizando a função serialize(). Esse método mágico exige que retornemos em um array definindo quais atributos do objeto devem ser serializados, caso não seja retornado, o objeto será serializado com o valor null. Veja um exemplo:


class Pessoa
{
    private $nome;
    private $peso;
    private $altura;

    public function __sleep()
    {
        return ["peso", "altura"];
    }
}

$pessoa = new Pessoa();

$resultado = serialize($pessoa);

echo $resultado;

// Resultado: O:6:"Pessoa":2:{s:12:"Pessoapeso";N;s:14:"Pessoaaltura";N;}

__wakeup()

Ao contrário do __sleep o método mágico __wakeup é chamado quando desserializamos um objeto utilizando a função unserialize(). Esse método mágico pode ser útil quando precisamos refazer o objeto e por algum motivo falta dados, ou perdemos a conexão com o banco, então podemos montar o objeto novamente, exemplo:


class Pessoa
{
    private $nome;
    private $peso = "80";
    private $altura = "1,80";

    public function __wakeup()
    {
        $this->nome = "Pedro";
    }
}

$pessoa = new Pessoa();

$pessoaSerializada = serialize($pessoa);
$resultado = unserialize($pessoaSerializada);

var_dump($resultado);

// Resultado: object(Pessoa)#2 (3) { ["nome":"Pessoa":private]=> string(5) "Pedro" ["peso":"Pessoa":private]=> string(2) "80" ["altura":"Pessoa":private]=> string(4) "1,80" }

__serialize()

Faz a mesma coisa que o método __sleep, caso a classe tenha os dois métodos definidos será chamado o __serialize e o método __sleep será ignorado. Observação: o método __serialize só está disponível a partir da versão 7.4 do PHP.


class Pessoa
{
    private $nome;
    private $peso;
    private $altura;

    public function __serialize()
    {
        return ["peso", "altura"];
    }

    public function __sleep()
    {
        return ["nome"];
    }
}

$pessoa = new Pessoa();

$resultado = serialize($pessoa);

echo $resultado;

// Resultado: O:6:"Pessoa":2:{i:0;s:4:"peso";i:1;s:6:"altura";}

__unserialize()

Faz a mesma coisa que o método __wakeup, caso a classe tenha os dois métodos definidos será chamado o __unserialize e o método __wakeup será ignorado. Observação: o método __unserialize só está disponível a partir da versão 7.4 do PHP.


class Pessoa
{
    private $nome;
    private $peso = "80";
    private $altura = "1,80";

    public function __unserialize()
    {
        $this->nome = "João";
    }

    public function __wakeup()
    {
        $this->nome = "Pedro";
    }
}

$pessoa = new Pessoa();

$pessoaSerializada = serialize($pessoa);
$resultado = unserialize($pessoaSerializada);

var_dump($resultado);

// Resultado: object(Pessoa)#2 (3) { ["nome":"Pessoa":private]=> string(5) "João" ["peso":"Pessoa":private]=> string(2) "80" ["altura":"Pessoa":private]=> string(4) "1,80" }

__toString()

Esse método é chamado quando você tenta imprimir um objeto como se fosse uma string, por exemplo, utilizando o echo ou print. Você deve retornar uma string, caso não retorne, a aplicação acusará um E_RECOVERABLE_ERROR, veja um exemplo:


class Pessoa
{
    public function __toString()
    {
        return "Você usou um objeto como string";
    }
}

$pessoa = new Pessoa();
echo $pessoa;

// Resultado: Você usou um objeto como string

__invoke()

Esse método é chamado quando você tenta usar um objeto como se fosse uma função, veja um exemplo:


class Pessoa
{
    public function __invoke()
    {
        echo "Você tentou usar um objeto como uma função";
    }
}

$pessoa = new Pessoa();
$pessoa();

// Resultado: Você tentou usar um objeto como uma função

__set_state()

Esse método mágico acredito ser o mais complicado de todos, na verdade ele não parece ser um método mágico. Ele deve ser definido como static. Esse método é chamado quando utilizamos a função var_export, que é semelhante ao var_dump, a diferença das duas funções é que o var_export retorna um código PHP válido, podendo ser executado com funções como eval que executa uma string como código PHP. Veja esse exemplo:


class Pessoa
{
    public $nome;
    public $idade;

    public static function __set_state($array)
    {
        echo "Você exportou a pessoa com o nome " . $array["nome"] . " e idade " . $array["idade"];
    }
}

$pessoa = new Pessoa();
$pessoa->nome = "Pedro";
$pessoa->idade = 25;

$pessoaExported = var_export($pessoa, true) . ";";

eval($pessoaExported);

// Resultado: Você exportou a pessoa com o nome Pedro e idade 25

No exemplo acima, o var_export irá trazer a seguinte string Pessoa::__set_state(array( 'nome' => 'Pedro', 'idade' => 25, ));. É um código PHP válido, então podemos executar com a função eval, que ao executá-la, irá chamar o método __set_state. Confuso não? Esse método não deveria ser um método mágico pois executamos ele como se fosse um método static normal.

__clone()

Esse método mágico é chamado quando você clona um objeto. Ele pode ser útil caso você queira alterar propriedades ou ações no novo objeto, exemplo:


class Pessoa
{
    public function __clone()
    {
        echo "Você clonou um objeto";
    }
}

$pessoa = new Pessoa();
$pessoa2 = clone $pessoa;

// Resultado: Você clonou um objeto

__debugInfo()

É chamado quando usamos o var_dump em um objeto para poder ver suas propriedades, nesse método mágico podemos alterar o que o var_dump exibirá, conforme exemplo:


class Pessoa
{
    private $altura = "1,80";

    public function __debugInfo()
    {
        return [
            "altura" => "2,00"
        ];
    }
}

$pessoa = new Pessoa();

var_dump($pessoa);

// Resultado: object(Pessoa)#1 (1) { ["altura"]=> string(4) "2,00" }

Conclusão

O PHP disponibiliza vários métodos mágicos, cada um para uma determinada situação, muitos frameworks usam esses métodos nas suas classes parecendo que são mágicos por fazerem coisas que nem entendemos, mas tudo isso está disponível para qualquer desenvolvedor utilizar, faça bom proveito!

Referência: https://www.php.net/manual/pt_BR/language.oop5.magic.php

Voltar para o topo