Utilzando o Design Pattern OBSERVER utilizando as interfaces SPL (STANDARD PHP LIBRARY)
Introdução:
Quando queremos avisar o termino de um método normalmente utilizamos return 1 ou return true, false, dentre outros processos que indicam que o processo foi executado ou em que parte do processo o código esta executando.
Pensando em uma estruturação de objetos esta prática pode ser considerada errada, pois isso é uma programação procedural dentro de um objeto.
Para enviarmos o fim da execução ou até mesmo em que "pé" esta o processo de atualização, inserção , Utilizaremos o Observer Pattern.
Definição:
A utilização é um objeto que será observado por um ou mais objetos , que são os observadores, que obviamente são associados como observadores deste objeto, e quando o observador disparar um método de notificação, todos os objetos associados (os observadores) executarão cada um sua rotina específica, assim fazendo com que o processo seja organizado e evitando colocar instancias de objetos dentro de outros objetos ou até mesmo um aninhado de instancias para cada objeto que irá executar algo.
Utilização:
Utilizarem duas interfaces já disponíveis no PHP chamadas de SplObserver e SplSubject, disponíveis dês do começo do PHP 5.1.xxxx
- Interface SplSubject: é a interface que será implementada no Observado. contém os metodos attach e detach e notify
-- attach: Adiciona observadores ao objeto.
-- detach: Remove observadores.
-- notify: Envia a notificação para todos os observadores do objeto.
- Interface SplObject: é a interface do observador. contém somente o método update.
NOTA : Todos os métodos dessas interfaces, são explícitos em relação aos métodos, chamados de type-hint, ou seja , para o método attach só deve ser enviado como parâmetro um objeto do tipo SplObserver, o mesmo para o detach, tudo isso existe uma documentação, e vou colocar um código de exemplo.
Desenvolvendo:
Vamos primeiro criar a classe que será observada pelos demais objetos, chamaremos ela de Materia
<?php
class Materia implements SplSubject {
private $nome_materia;
// Os observadores é um array onde ele guardará todas as instâncias dos objetos que forem adicionados
private $_observadores =
array();
// Coloquei um array de log só para mostrar o funcionamento do Observer
// Encapsuladores
public function GET_materia()
{
return $this->nome_materia;
}
function SET_log($valor){
$this->_log[] = $valor ;
}
function GET_log(){
return $this->_log;
}
// Função construtora que irá somente associar um nome ao professor
function __construct($nome){
$this->nome_materia = $nome;
$this->_log[] = " Materia $nome foi incluida com sucesso";
}
// Implementa o método attach do SplSubject, enviando como parâmetro um observador e associando ao array de objetos
public function attach(SplObserver $classes){
$this->_classes[] = $classes;
$this->_log[] = " O ".$classes->GET_tipo()." ".$classes->GET_nome()." foi adicionado";
}
// Implementa o método detach do SplSubject, que somente remove a instância do objeto
public function detach(SplObserver $classes){
foreach ($this->_classes as $key => $obj){
if ($obj == $classes){
unset($this->_classes
[$key]);
$this->_log[] = " O ".$classes->GET_tipo()." ".$classes->GET_nome()." foi removido";
}
}
}
// Implementa o método notify do SplSubject, que percorre todo o array de observadores e chama o método update de do observador, que esta implementado dentro da sua classe
public function notify(){
foreach ($this->_classes as $classes){
$classes->update($this);
}
}
}
?>
Feito isso, criaremos uma classe de Professor.
<?php
class Professor implements SplObserver{
protected $tipo = "Professor";
private $nome;
private $endereco;
private $telefone;
private $email;
// Encapsulador
public function GET_tipo(){
return $this->tipo;
}
public function GET_nome()
{
return $this->nome;
}
public function GET_email()
{
return $this->email;
}
public function GET_telefone()
{
return $this->nome;
}
// Construtor que somente associa o nome do professor
function __construct($nome) {
$this->nome = $nome;
}
// Implementa o método update do SplObserver, que executa o método de acordo com a necessidade do objeto Professor
public function update(SplSubject $object){
$object->SET_log("Vindo de ".$this->nome.": Dou aula de ".$object->GET_materia());
}
}
?>
Criaremos agora uma classe de Aluno.
<?php
class Aluno implements SplObserver{
protected $tipo = "Aluno";
private $nome;
private $endereco;
private $telefone;
private $email;
// Encapsulador
public function GET_tipo(){
return $this->tipo;
}
public function GET_nome()
{
return $this->nome;
}
public function GET_email()
{
return $this->email;
}
public function GET_telefone()
{
return $this->nome;
}
// Construtor que somente associa o nome do aluno
function __construct($nome) {
$this->nome = $nome;
}
// Implementa o método update do SplObserver, que executa o método de acordo com a necessidade do objeto Aluno
public function update(SplSubject $object){
$object->SET_log("Vindo de ".$this->nome.": Sou aluno de ".$object->GET_materia());
}
}
?>
Com as classes criadas, iremos associar os observadores na classe observada e depois notificaremos.
<?php
require_once("professor.class.php");
require_once("aluno.class.php");
require_once("materia.class.php");
$materia = new Materia("Matematica");
$marcus = new Professor("Marcus");
$rafael = new Aluno("Rafael");
$vinicius = new Aluno("Vinicius");
// Associando os observadores no objeto Materia Matemática
$materia->attach($rafael);
$materia->attach($vinicius);
$materia->attach($marcus);
$materia2 = new Materia("Portugues");
$renato = new Professor("Renato");
$fabio = new Aluno("Fabio");
$tiago = new Aluno("tiago");
// Associando os observadores no objeto Materia Portugues
$materia2->attach($renato);
$materia2->attach($vinicius);
$materia2->attach($fabio);
$materia2->attach($tiago);
// Removendo Alunos da Materia 1
$materia->detach($rafael);
// Notificando as 2 Matérias
$materia->notify();
$materia2->notify();
?>
O output esperado é esse:
Materia 1
(
[0] => Materia Matematica foi incluida com sucesso
[1] => O Aluno Rafael foi adicionado
[2] => O Aluno Vinicius foi adicionado
[3] => O Professor Marcus foi adicionado
[4] => O Aluno Rafael foi removido
[5] => Vindo de Vinicius: Sou aluno de Matematica
[6] => Vindo de Marcus: Dou aula de Matematica
)
Materia 2
(
[0] => Materia Portugues foi incluida com sucesso
[1] => O Professor Renato foi adicionado
[2] => O Aluno Vinicius foi adicionado
[3] => O Aluno Fabio foi adicionado
[4] => O Aluno tiago foi adicionado
[5] => Vindo de Renato: Dou aula de Portugues
[6] => Vindo de Vinicius: Sou aluno de Portugues
[7] => Vindo de Fabio: Sou aluno de Portugues
[8] => Vindo de tiago: Sou aluno de Portugues
)
Esse é um exemplo simples de como utilizar um observer sem precisar colocar uma instância do professor e aluno dentro da matéria.
Pode ser feito muito mais com isso, como por exemplo um observer que ao cadastrar uma pessoa , envia um email para o admin. Use a imaginação e espero que gostem
Qualquer dúvida, crítica,sugestão ou incentivo para escrever mais artigos: mvbdesenvolvimento@gmail.com
Abraços