OOP no PHP: Overloading, utilizando os métodos mágicos do PHP

E aeeeeew blz? Bom gente voltando do período de preguiça bagarai, vício em jogos online e outras vagabundagens ociosidade vamos dar continuidade a série de artigos sobre OOP no PHP. O assunto de hoje é bem interessante, no post de hoje vamos ver como usar um dos métodos mágicos do php.

Neste artigo vou falar do método mágico __call(),  que funciona da seguinte maneira:

Quando uma classe tem o método __call() o php roda esse método sempre que qualquer método da classe for chamado, mesmo se o método que foi chamado não existir um método inexistente ou inacessível for chamado (obrigado Edgar pelo puxão de orelha), isso abre espaço para algumas coisas interessantes.

Vamos a um exemplo do funcionamento de __call():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
class ExemploCall {  
  function __call($m, $a)
  {
    print "Método chamado: $m\n";
    print "Parametros: \n";
    var_dump($a);
    return $this->x;
  }
}
$call = new ExemploCall();
$call->test(1,2,'teste');
 
//Mostra na tela
/*
Método chamado: test 
Parametros: 
array(3) { 
  [0]=>  int(1) 
  [1]=>  int(2) 
  [2]=>  string(5) "teste" 
} 
*/
?>

O exemplo acima simplesmente exibe na tela o método chamado e os parametros enviados, mas vendo isso a pergunta que surge na cabeça é, pra que ou onde eu vou usar o método __call()?

A resposta pra essa pergunta vai da sua criatividade mas eu vou postar aqui uma forma de uso que o cakephp usava há algum tempo atrás.

Funcionava da seguinte forma, havia um método padrão chamado find que era chamado e fazia consultas ao banco de acordo com os parametros passados, porém, (aqui que vem a mágica) ele também podia ser chamado como findByNomeDoCampo o que em alguns momentos facilitava bastante a vida do programador, vamos fazer algo parecido com isso.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<?php
 
/**
  Só vou postar o código relevante aos métodos mágicos, mas supõe-se que
  deste ponto em diante você já tem incluido no arquivo toda a rotina de 
  conexão com o banco de dados, etc, etc, etc...  
**/
 
class Model {
 
  public function __construct() 
  { //O conteúdo deste método vai variar de acordo com sua classe
  }
 
  public function __call($method, $params)
  {
    // Verifica se o método chamado existe nessa classe
    if ( method_exists($this,$method) )
    {
      //Caso exista chama o método
      return call_user_method($method, $this, $params);
    } 
    else 
    {
      //Caso não exista, chama um método especial que fará a nossa mágica
      $this->parseMethods($method,$params);
    }
  }
 
  private function parseMethods($method,$params)
  {
    //Verifica se o método segue o padrão adotado
    if ( eregi('findBy',$method) === false ) 
    {      
      //Caso não siga dispara um erro dizendo que o método é inválido/não encontrado
      trigger_error('Método inválido ou inexistente',E_USER_ERROR); 
      die;
    }
    else
    {
      //Caso seja um método padronizado (findByAlgo) recupera o nome do campo e converte tudo para minúsculo
      $fieldName = strtolower(str_ireplace('findBy','',$method));      
 
      //Formata os parametros para serem passados ao método find padrão
      $options = $params['1'];
      $options['conditions'] = array($fieldName=>$params['0']);
 
      //Chama o método find original
      $this->find($options);            
    }
  }
 
 
  public function find($options) 
  {    
    var_dump($options);
    //Aqui você faria a consulta usando as informações recebidas
  }
 
}
 
//Instancia a classe
$model = new Model();
 
//Define parametros a serem passados
$options = array (
   'fields' => array ('*')
  ,'order'  => array ('nome ASC')
);
 
//Chama o método mágico
// Onde o primeiro parametro é o valor que o campo passado no nome do método deve ter.
$model->findByBlog('Technócio',$options);
 
/**
O que chega no método options é:
array(3) { 
    ["fields"] =>  array(1) { 
        [0]=>  string(1) "*" 
    } 
    ["order"] =>  array(1) { 
        [0]=>  string(8) "nome ASC" 
    } 
    ["conditions"] =>  array(1) { 
        ["blog"]=>  string(9) "Technócio" 
    } 
} 
**/
?>

O código ta bem comentado e bem simples também, embora não tenha me aprofundado muito no assunto acho que deu pra ter uma noção dessa possibilidade e do que pode ser feito com isso.

Como sempre, para dúvidas, sugestões e puxões de orelha, utilizem os comentários. Até a próxima (que dessa vez não vai ser tão demorada assim).