2008-08-23 03:55:02
tags: 

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 27)

Para ver os artigos anteriores desta série, clique aqui.

Olá meus caros amigos. Depois das decepções do salto com vara, do pentatlo moderno, do hóquei na grama, do salto triplo, do badminton, do baseball, do basquete, do bmx, do badminton, do taekwondo, do karatê, do salto em altura, do revezamento 4x100m, dos 800m, do tiro, do nado sincronizado, da ginástica rítmica e artística, da luta greco-romana, luta livre, esgrima, do arco e flecha, do boxe, da canoagem, do cliclismo, do softball, do levantamento de peso, do tênis, do triatlon, do tênis de mesa, do remo, do handball, do trampolim e finalmente, do futebol, voltamos aqui pra falar do que o brasileiro realmente entende: OOP, o famoso esporte da programação orientada a objetos.

Nas últimas semanas estivemos vendo alguns recursos que já vem na caixa do PHP quando você compra: as bibliotecas SPL são um bom exemplo. Mas o PHP é igual às olimpíadas: quanto mais popular é a necessidade, mais chance de entrar na instalação padrão do PHP. E uma das funcionalidades mais importantes em qualquer sistema é a conectividade com sistemas de banco de dados.

Pra isso, os nossos amigos discípulos do Boerger desenvolveram uma camada de abstração chamada PDO. Pra gente entender o que é PDO, portanto, precisamos entender primeiro o que é uma camada de abstração, correto?

Muito bem, caros leitores, nesse momento preciso contar uma verdade dura para vocês: o mundo lá fora é feio e sujo. Sim, acreditem! Não existem padrões, cada programador reinventa a roda a cada dia para provar que é o melhor! Bancos de dados, por exemplo: eu que sou um desconhecedor completo do assunto conheço pelo menos 10 sistemas gerenciadores de banco de dados, todos eles muito bons e com características próprias bastante singulares. A única coisa que tenho certeza que todos têm em comum é a capacidade de executar alguns comandos SQL de forma similar.

Uma camada de abstração para sistemas de banco de dados faz com que seu código use os mesmos métodos para acessar informações em qualquer um dos bancos de dados disponíveis. Assim, você poderia até mudar de sgbd sem ter que mudar seu código, e tudo funcionaria perfeitamente.

Claro que alguns bancos de dados não fazem as mesmas coisas que outros; alguns são mais poderosos, com mais possibilidades, outros mais simples. Portanto, uma boa camada de abstração tenta disponibilizar somente as funcionalidades que podem ser utilizadas de forma universal, ou, em alguns casos, emular as funcionalidades mais avançadas que não estão disponíveis nos bds mais simples.

Enfim, vocês sacaram?

A sigla PDO significa PHP Data Objects. Com os tais PDOs a gente tem uma forma padronizada e orientada a objetos para acessar os bancos de dados mais legais do planeta. E ganha de brinde um monte de funcionalidades interessantes. Veja um exemplo de conexão:

<?php
try {
    $meuObjetoPDO = new PDO('mysql:host=localhost;dbname=teste', $usuario, $senha);
    foreach($meuObjetoPDO->query('SELECT * from produtos') as $produto) {
        print_r($produto);
    }
    $meuObjetoPDO = null;
} catch (PDOException $e) {
    print "Deu zebra: " . $e->getMessage() . "
";
    die();
}
?>
    

 

O código acima abre uma conexão MySql e faz um select na tabela Produtos, que retorna um objeto PDO com os dados e um monte de outras propriedades. Qual a grande vantagem? Lembra como a gente fazia para acessar um bd em php? Tinhamos que usar os comandos Mysql:

<?php
$minhaconexao = mysql_connect('localhost', 'usuario', 'senha')
    or die('Erro de conexão: ' . mysql_error());
echo 'Beleza! Conectado!';
mysql_select_db('teste') or die('Não consegui selecionar o bd...');

// Performing SQL query
$query = 'SELECT * FROM produtos';
$resultado = mysql_query($query) or die('Erro na Query: ' . mysql_error());

// Printing results in HTML
while ($produto = mysql_fetch_array($resultado, MYSQL_ASSOC)) {
print_r($produto);
}

// Free resultset
mysql_free_result($resultado);

// Closing connection
mysql_close($minhaconexao );
?>
    

Até aí, já dá pra ver que usar PDO é mais fácil, mas ainda está faltando o nocaute: seu chefe chega pra você e diz, "ô fulano, vai mudar o bd, troca aí pra Oracle!".

Usando PDO, vc simplesmente troca a primeira linha e tá tudo pronto. No segundo caso... prepare-se para mudar um milhão de linhas.

Abraço grande e até semana que vem!

2008-08-16 04:18:50
tags: 

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 26)

Para ver os artigos anteriores desta série, clique aqui.

Ah, as olimpíadas. Atletas abnegados que se dedicaram durante anos para tentar a glória. Toda uma vida de treinos e sacrifícios é colocada à prova em frações de segundos. Um mísero erro, e toda a preparação vai por água abaixo.

A vida destes atletas, meus caros, guardadas as devidas proporções de massa muscular e gordura corporal, é parecida com a vida dos programadores. Um mísero erro, e todo o banco de dados vai pro saco. Um segundo a mais de performance perdida, e o servidor não aguenta o tranco. Portanto, meus atléticos leitores, ao celebrar as olimpíadas e virar a noite para ver aquele jogaço de hóquei na grama feminino não se esqueça: parte do solo sagrado do olimpo também é sua!

Ruminâncias sem nexo à parte, hoje quero mostrar mais uma jogada da biblioteca SPL pra vocês. Lembram-se do nosso carrinho de compras? Bem, respeitáveis atletas, preciso dizer que ele não aguentou a pressão na final e se enrolou todo. Explico: do jeito que construímos este carregador de objetos, ele falha miseravelmente se a gente simplesmente incluir o mesmo objeto mais de uma vez. Experimente. Duplique a linha abaixo e veja o carrinho se comportar de forma muito estranha, listando o mesmo item duas vezes. Cartão vermelho.

Pra dizer a verdade, já existe um cara na SPL que faz essa função de carrinho de compras (e, claro, de qualquer outro conteiner de objetos que você quiser) de forma muito mais esperta. É a classe SplObjectStorage.

Uma coisa que essa classe faz é exatamente controlar os objetos que nela são guardados para evitar que o mesmo objeto seja incluído duas vezes. Mais do que isso, ela controla também updates; se você alterar o objeto e adicionar novamente à coleção a classe automaticamente atualiza os dados pra você. Ippon!

Veja só que beleza:


class CarrinhoDeCompras extends SplObjectStorage {

    // nosso carrinho de compras é, no fundo, um array de objetos da classe Item...
    private $carrinho = array();
    
    //coloca um Item no carrinho
    //usando type hinting, viu o Item antes da variavel? Isso diz que essa função só aceita objetos da classe Item...
    
    public function adicionaItem(Item $item){
    
     $this->attach($item);
    
    }
    
    //detona tudo no carrinho
    
    public function esvaziaCarrinho(){
    
     unset ($this->storage);
    
    }
    
    // ué cade o resto todo? Não precisa cara. A classe SplObjectStorage já traz tudo de brinde: ArrayAccess, Iterator e muito mais!
    
// uma inclusão boa pra nos aqui: que tal colocar a logica de impressao do carrinho logo aqui?
    public function __toString(){

     foreach($this as $item) { // <- $meucarrinho é um array? é um objeto? como???
        $string .= "
" . "Código: " . $item->getCodigo() . " Descrição: " . $item->getDescricao() ." Preço: " . $item->getPreco() . " Quantidade: ". $item->getQuantidade();
        $total += $item->getPreco() * $item->getQuantidade();
     }

     $string = $string . "
" . "O total da sua compra é: " . $total;
    
     return "
" . $string . "
";
    }


}


class Item {

    private $codigo;
    private $descricao;
    private $preco;
    private $quantidade;
    
    public function __construct($codigo,$descricao,$preco,$quantidade){
     $this->codigo = $codigo;
     $this->descricao = $descricao;
     $this->preco = $preco;
     $this->quantidade = $quantidade;
    }
    
    public function getCodigo(){
    
     return $this->codigo;
    
    }
    
    public function getDescricao(){
    
     return $this->descricao;
    
    }
    
    public function getPreco(){
    
     return $this->preco;
    
    }

    public function getQuantidade(){
    
     return $this->quantidade;
    
    }
    
    public function setQuantidade($quantidade){
     $this->quantidade = $quantidade;    
    }


}

//Muito bem, agora vamos la!


$meucarrinho = new CarrinhoDeCompras();

//aqui, pra provar nosso ponto, vamos ter que instanciar os objetos em variaveis pra poder tentar adicionar novamente o mesmo objeto

$item1 = new Item('1','Caneta Bic Azul','1.00','10');
$item2 = new Item('2','Caneta Bic Vermelha','1.50','5');
$item3 = new Item('3','Caneta Bic Quatro Cores','3.50','15');

$meucarrinho->adicionaItem($item1);
$meucarrinho->adicionaItem($item2);
$meucarrinho->adicionaItem($item3);


print $meucarrinho;

// agora a prova!

$item1->setQuantidade(30);
$meucarrinho->adicionaItem($item1);

print $meucarrinho;


?>

É isso aí pessoal! Até a próxima!

2008-08-09 03:58:25
tags: 

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 25)

Para ver os artigos anteriores desta série, clique aqui.

Respeitável público! Senhoras e Senhores! Rapazes e Raparigas de todo o Brasil! Com vocês, no palco do Circo Orientado a Objeto Ringling Bros. PHP, o fantástico mago transformador de objetos, o rei das interfaces spl, o grande Rasmussen! Vejam como ele transforma qualquer objeto em um array com apenas algumas linhas de código!


class CarrinhoDeCompras implements ArrayAccess, Countable {

    // nosso carrinho de compras é, no fundo, um array de objetos da classe Item...
    private $carrinho = array();
    
    //coloca um Item no carrinho
    //usando type hinting, veja o Item antes da variavel $item abaixo. Isso diz que essa função só aceita objetos da classe Item...
    
    public function adicionaItem(Item $item){
    
     $this->carrinho[] = $item;
    
    }
    
    //detona tudo no carrinho
    
    public function esvaziaCarrinho(){
    
     unset ($carrinho);
    
    }
    
    /*
    Aqui entram as funções obrigatórias da interface ArrayAccess e Countable.
    ArrayAccess: offsetExists, offsetGet, offsetSet, offsetUnset
    Countable: count
    Lembre-se: as interfaces exigem que voce use exatamente estes nomes para as funções!
    */


    //Existe o item numero $indice? offsetExists responde:

    public function offsetExists($indice) {

     return isset($this->carrinho[$indice]);

    }


    //Me dá ai o ítem $indice:

    public function offsetGet($indice){

     return $this->carrinho[$indice];

    }


    //Muda o item numero $indice para esse item aqui ó

    public function offsetSet($indice,$item) {

     if ($indice){

        $this->carrinho[$indice] = $item;

     }

     else {

        throw new Exception('Precisamos do indice para inserir o item no lugar certo...');

     }
    }
    
    
    // detona o item número $indice
    
    public function offsetUnset($indice) {
    
     unset($this->carrinho[$indice]);
    
    }
    
    
    // conta o numero de itens (obrigatório pela interface countable)
    
    public function count(){
    
     return count($this->carrinho);
    
    }
    
}


class Item {

    private $codigo;
    private $descricao;
    private $preco;
    private $quantidade;
    
    public function __construct($codigo,$descricao,$preco,$quantidade){
     $this->codigo = $codigo;
     $this->descricao = $descricao;
     $this->preco = $preco;
     $this->quantidade = $quantidade;
    }
    
    public function getCodigo(){
    
     return $this->codigo;
    
    }
    
    public function getDescricao(){
    
     return $this->descricao;
    
    }
    
    public function getPreco(){
    
     return $this->preco;
    
    }

    public function getQuantidade(){
    
     return $this->quantidade;
    
    }


}

//Muito bem, agora vamos la!


$meucarrinho = new CarrinhoDeCompras();
$meucarrinho->adicionaItem(new Item('1','Caneta Bic Azul','1.00','10'));
$meucarrinho->adicionaItem(new Item('2','Caneta Bic Vermelha','1.50','5'));
$meucarrinho->adicionaItem(new Item('3','Caneta Bic Quatro Cores','3.50','15'));

//Agora, caros amigos, a mágica:

$total = 0;
        for($i=0; $i<count($meucarrinho); $i++) { //<- $meucarrinho é um array? é um objeto? como???
         print "Código: " . $meucarrinho[$i]->getCodigo() . " Descrição: " . $meucarrinho[$i]->getDescricao() ." Preço: " . $meucarrinho[$i]->getPreco() . " Quantidade: ". $meucarrinho[$i]->getQuantidade();
         $total += $meucarrinho[$i]->getPreco() * $meucarrinho[$i]->getQuantidade();
}

print "O total da sua compra é: " . $total;

?>

Muito bom, não? Mas antes que vocês saiam por aí contando pra todo mundo que descobriram como se faz o truque, experimentem usar este objeto dentro de um foreach. Não rolou, certo? Você tem alguma idéia do porque? Muito bem, caro aprendiz! Você precisa implementar a interface Iterator, que falamos na semana passada, para que este objeto realmente se transforme em um Array completo!

Até semana que vem!


2008-08-02 02:52:05
tags: 

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 24)

Para ver os artigos anteriores desta série, clique aqui.

Caríssimos amigos, aqui estamos de volta. Na nossa última conversa, começamos a falar destes fantásticos seres mitológicos, os Iterators. Espero que nossos exemplos tenham ajudado a entender o conceito básico por trás deste Design Pattern tão importante.

Mas agora chegou a hora de aproveitar. Nosso caro Sr. Marcus Boerger, quando criou as extensões SPL, nos deu muita coisa de brinde. Não só temos agora interfaces padronizadas para um grande número de implementações de patterns, como ganhamos também uma série de classes prontas para usar. E quando falamos de iterators, temos muita coisa boa, meus amigos! Veja o exemplo abaixo:

 
	try{
$file = new SplFileObject( "/digitalminds/texto.txt" );
$numlines = 0;
foreach ($file as $line){
$numlines ++;
}
$linenum = rand(1,$numlines);
$file->seek($linenum);
//essa linha vai ser enviada por email
mail('danilo@digitalminds.com.br', 'Assunto aqui!', $file->current());
} catch (Exception $e) {
echo $e->getMessage();
}
?>

 

Veja a beleza do que está acontecendo: ao instanciar o objeto SplFileObject, tenho prontinho um iterator que posso jogar diretamente num foreach para contar as linhas, imprimí-las, ou, usando a função $file->seek() posso pegar uma linha específica do arquivo e, no caso particular acima, enviá-las por email pra mim mesmo.

Vocês repararam que eu nem sequer pedi pra abrir o arquivo? Tá tudo pronto. E tem muito mais: esta classe tem quase 100 outros métodos que servem pra escrever no arquivo, ver as propriedades, pegar o diretório no qual ele está... experimente fazer nesse exemplo aí de cima um

print_r(get_class_methods($file) );

pra ver todos os métodos disponíveis. Ou, clique aqui e desça o scroll até a lista de funções.

E não é só isso, meus caros: vocês conseguem imaginar o que as classes DirectoryIterator, RecursiveDirectoryIterator, SimpleXMLIterator e SplFileInfo podem fazer? E que todas elas, ao serem instanciadas, te dão um objeto que funciona direitinho em um foreach ou um while? Entenderam o lance?

Muito bem. Divirtam-se com seus novos amigos. Na semana que vem, vamos aprender como transformar qualquer objeto em um array. Abraços a todos.

 

2008-07-26 04:50:57
tags: 

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 23)

Para ver os artigos anteriores desta série, clique aqui.

Ah, os iterators. Iterators, meus amigos. Como vários outros conceitos desta enigmática arte da programação orientada a objeto, os iterators são quase incompreensíveis para gente como eu - cujo único treinamento foi nas ruas, entre códigos incompreensíveis, brigas de puxar cabelo e gambiarras que mais pareciam aquelas geringonças que os vilões de desenho animado inventam para eliminar seus inimigos (quase sempre sem sucesso, é claro).

Ainda não posso dizer que entendo os iterators em toda sua grandeza. Seus significados ocultos ainda me deixam perplexo de tempos em tempos. Mas que exercícios intelectuais fascinantes eles podem nos proporcionar! Que enigmas incríveis eles nos reservam, que tesouros escondidos!
Se você ainda está lendo, acho que consegui prender sua atenção com estas baboseiras. Vocês jovens precisam de um pouco de nonsense pra prestar atenção nas coisas. Enfim. Iterators.
Pra resumir: Iterators "pegam" uma coleção de objetos e permitem que você faça operações com cada um eles. Vou dar um exemplo, porque esse conceito sempre foi pra mim muito difícil de entender. Digamos que você seja um comerciante libanês. Na sua lojinha, que fica ali na S.a.a.r.a., você vende tudo, desde açafrão em pó até relógio digital. Depois de comer 15 esfihas, folha de uva, coalhada seca, arroz com lentilha e 3 caftas no Cedro do Líbano, você resolve fazer uma contagem do estoque. Sabe como é, nesses dias de hoje, não dá pra confiar. Aí você chama o seu gerente de eletrônicos, o Sr. Salim e fala o seguinte:

- Ô Salim! Pra cada relógio aí do estoque faz o seguinte: vê se o ponteiro tá mexendo, depois vê se tá arranhado e aí coloca na caixinha de novo. Depois você me diz quantos estão bons!

Muito bem. Qual é o grande problema deste approach, caro Amir? Qualquer comerciante libanês sabe - se eu tenho que dizer tudo o que o Salim tem que fazer, pra que diabos eu tenho um gerente? E se eu tiver 15 gerentes, imagina o tempo que eu vou perder pra explicar pra cada um como ver se o produto está bom?
O que você quer, meu caro amigo mercador, é perguntar quantos estão bons, e o seu gerente te responder, independentemente de qual linha de produtos ele gerencie. Sem que você precise explicar tudo toda hora.
Deu pra sacar a diferença? Agora, um exemplo muito prático que todo mundo usa pra explicar a utilidade dos iterators em php:
Imagine que você tem um site que pega dados de três tipos de fontes diferentes: arrays, banco de dados e diretórios no servidor. Assim:


/* array */
foreach ( $relogios as $relogio) {
     // faz alguma coisa com $relogio
}

/* MySQL */
while ( $tempero = mysql_fetch_array($result) ) {
     // faz alguma coisa com $tempero
}

/* Diretorio */
while ( false !== ($brinquedo = readdir($dir)) ) {
     // faz alguma coisa com $brinquedo
}

?>

Olha para esses caras aí em cima. Não dá pra sentir que tem alguma coisa parecida entre eles? Então, imagine que você quer pegar o nome de cada um desses caras aí em cima e imprimir na tela. Isso mesmo, você quer pegar o nome tanto dos relógios que estão no array, quanto dos temperos que estão no banco de dados e ainda dos brinquedinhos que são arquivos em um diretório no servidor.
O que você faz, meu caro? Coloca dentro de cada loop um print()? De jeito nenhum! Imagina se amanha você quiser mudar o formato da impressão, vai ter que mudar 3 vezes! Ou pior, imagine se a sua loja tiver 469 tipos de produto, o que é bem comum nessas lojas - Vai colocar 469 prints? Ah, já sei - você pensou que pode simplesmente fazer uma função para imprimir e colocar dentro de cada loop! Cuidado! meu caro, você está flertando com o diabo! Você está se afastando do sagrado caminho da OOP! Comece a colocar código que não é realmente a função da classe dentro dela e em breve você estará deitado numa cama de pregos, tostando lentamente no fogo do inferno!
A solução, meus caros amigos, é muito bonita. Senhores, apresento-lhes os Iterators!

$itens['brinquedos'] = new MeuDirectoryIterator($briquedos_diretorio); // aqui a fonte de dados é um diretório
$itens['relogios'] = new MeuArrayIterator($relogios_array); // aqui a fonte de dados é um array
$itens['temperos'] = new MeuMysqlIterator($temperos_query); // aqui a fonte de dados... ah, você já entendeu.

foreach($itens as $iterator){
    
     foreach($iterator as $item){
         print $item->getName();
     }

}
?>

Não é fantástico? Que magia existe nessas classes que permite tanta padronização? Vocês entenderam o que está acontecendo? Eu não preciso me preocupar com a forma dos dados! Vale tudo! Diretórios, arrays, resultados do Mysql, e se a gente quisesse, poderíamos incluir aí XML, YAML, enfim, vale tudo! Como assim! Isso é genial! Nunca mais vou repetir código novamente! No próximo capítulo da nossa série, vamos construir as classes MeuDirectoryIterator, MeuArrayIterator e MeuMysqlIterator e conhecer em detalhes este sensacional truque. Até lá, caro Amir!
2008-01-09 11:15:42

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 22)

                

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 22)

Para ver os artigos anteriores desta série, clique aqui.

Olá amigos. Estamos de volta depois de muita farofa, bacalhau, doce de leite, maionese, pamonha, queijo cavalinha, uma nova geladeira que não chega, livros e muita alegria. Espero que todos tenham passado dias maravilhosos nesse fim-de-ano e que possam ter aproveitado esses dias pra curtir a família e os amigos!

Mas chegou a hora de voltar para o batente. Antes que vocês comecem a mandar os já tradicionais emails "Cadê o 22! Queremos o 22!" eu já estou escrevendo mais um capítulo desta série singela, que procura explicar os conceitos mais enrolados de orientação a objetos em uma linguagem que todos aqui possam facilmente entender. E, pra ser bem honesto, os emails cobrando o 22 na verdade já começaram a chegar, então a hora é essa. Não estou reclamando de vocês de forma alguma, caros leitores! A pressão ajuda! Obrigado a todos que cobram, que agradecem, que mandam correções e puxões de orelha, sua contribuição faz disso aqui um lugar melhor.

Ah, o Natal. Que loucura que é o Natal. Falar sobre oop aqui no Digitalminds sempre é divertido porque eu tenho que bolar metáforas interessantes pra que o assunto não fique chato no primeiro parágrafo.  Então, como não poderia deixar de ser, o artigo de hoje está em clima de Natal. Não, eu não estou maluco, eu sei que o Natal já passou. Mas a segunda semana de janeiro não tem muita coisa interessante pra nos oferecer, a não ser que você conte o Dia de Reis.

O DIA DE REIS! É isso! Meu Deus como pude esquecer! Muito bem, senhores, esqueçam o natal. É hora de falar de Belchior (ou Melchior), Gaspar e Baltazar.
Não, senhores, não estamos falando de Belchior, nem de Gaspar, ou mesmo de Baltazar. Estamos falando de três magos persas, sacerdotes de Zaratrustra, homens sábios que conheciam profundamente a astrologia e que vislumbraram um sinal - na noite do dia 25 de dezembro do ano 1, souberam pelo brilho da estrela de Belém que um Rei nascera. E para comprovar que a wikipedia é sempre uma diversão, veja este parágrafo:

A melhor descrição dos reis magos foi feita por São Beda, o Venerável (673-735), que no seu tratado “Excerpta et Colletanea” assim relata: “Melchior era velho de setenta anos, de cabelos e barbas brancas, tendo partido de Ur, terra dos Caldeus. Gaspar era moço, de vinte anos, robusto e partira de uma distante região montanhosa, perto do Mar Cáspio. E Baltazar era mouro, de barba cerrada e com quarenta anos, partira do Golfo Pérsico, na Arábia Feliz”.

Uau. Sábios, caldeus, Ur, Pérsia. Agora que consegui a atenção total e irrestrita de vocês, futuros reis magos da OOP, e cobri todos de Incenso e Mirra, é hora de falar de uma classe importantíssima que ficou faltando no nosso grande esquema das coisas: a venerável classe ModelCollection.

Lembram que optamos por simplificar as funcionalidades da classe Model, fazendo com que ela realizasse operações somente em registros únicos no banco de dados? Muito bem, senhores, a classe ModelCollection aparece para nos salvar nos casos em que precisamos trabalhar com conjuntos de registros. Aqui é bom repetir o aviso: esta implementação é diferente da utilizada nos frameworks que utilizam o pattern ActiveRecord, como o Cake. Nestes frameworks todas as operações com registros e conjuntos de registros são feitas pela classe Model e suas subclasses. Assim, um objeto da classe model típico destes frameworks tem funções tanto para buscar, editar, salvar e deletar um registro quanto para buscar conjuntos de registros. Isso faz com que o objeto da classe que estamos usando não tenha um mapeamento direto com os dados que estão no banco. Isso me incomoda muito, pois eu gosto de pensar no objeto como uma coisa, uma representação virtual dos dados que estão no banco. Pra mim é estranho usar o modelo para retornar uma lista de registros. A nossa implementação vai claramente mapear um registro no banco a um objeto da classe correspondente, e um conjunto de registros a uma coleção de objetos da classe correspondente. Exemplo: nossa classe Post. Teremos no banco a tabela Posts, com os campos title e text, por exemplo. Para acessar e alterar  o campo de título de um post em nosso framework vamos seguir os seguintes passos:

  1. Criar um novo objeto da classe Post fazendo $post = new Post();
  2. Carregar os dados do registro que queremos alterar com id número $id  usando $post->loadById($id);
  3. Mudar o título usando $post->setTitle("Novo Título!");
  4. Salvar o post com $post->save();
Para criar um novo post, é simples:
  1. Criar um novo objeto da classe Post fazendo $post = new Post();
  2. Mudar o título usando $post->setTitle("Título do Novo Post!");
  3. Mudar o texto usando $post->setText("Texto do Post!");
  4. Salvar o post com $post->save();
Nessa implementação vamos poder acessar as variáveis do objeto usando getters normalmente, por exemplo, $post->getTitle(); Podemos também criar vários atalhos: o construtor do Post pode receber  o Id diretamente e já carregar os dados automaticamente. Podemos implementar a interface ArrayAccess para permitr coisas como print $post['title'] sem nenhuma dificuldade. Enfim. A coisa é boa. Aguardem que vem coisa ótima por aí.
Mas até aí, nenhuma novidade. O que muda é a forma de trabalhar com conjuntos de dados. No Cake, esse trabalho seria feito por funções na classe Post que retornariam Arrays contendo vários ítens. E isso deixa tudo confuso, no final das contas. O que proponho é o seguinte:
  1. Criar um novo objeto da classe PostCollection fazendo $collection = new PostCollection();
  2. Carregar o conjunto de registros usando uma das várias funções disponíveis, por exemplo $collection->loadAll();
Muito simples. E agora temos um objeto da classe PostCollection carregado de registros, com métodos super úteis para manipular os dados, paginar, enfim, uma belezinha. E vamos implementar uma coisa sensacional: a interface iterator, disponível na fantástica biblioteca SPL, proveniente de UR, na Pérsia! Mas isso já é assunto para o próximo episódio. Até lá!


2007-12-04 02:20:34

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 21)

Para ver os artigos anteriores desta série, clique aqui.

Olá amigos. Em nosso último encontro finalizamos nossa primeira análise das classes principais do MVC: Model, View e Controller. Sei que muitos de vocês estão ansiosos para começar a codificar mas ainda temos bastante mufa pra queimar antes de começar a digitar código php!

Bom, pra começar, um pouco da história do cinema: quem não se lembra de Sean Connery como o policial irlandês em Os Intocáveis ? E de Kevin Spacey, como o bobalhão "Verbal" em Os Suspeitos ? E de Gene Hackman como o xerife mau, muito mal de Os Imperdoáveis ? Muito bem, o que esses três papéis interpretados por estes grandes atores têm em comum? As três interpretações foram premiadas com Oscars de melhor ator coadjuvante. E por quê todo este papo cinematográfico? É que hoje vamos falar de uma classe coadjuvante que é fundamental em nosso quase-framework: nosso amigo Dispatcher.

Muito bem, como já falamos algumas vezes, nosso framework é bastante esperto: ele vai permitir que acessemos métodos de nossos controllers simplesmente interpretando uma URL. Por exemplo, para acessar o método view() do controller BlogPost para ver o post com o id 19 nossa url seria

http://nossoblog.com.br/blogpost/view/19

Ok, mas quem transforma uma coisa na outra? Quem chama o que? Como isso funciona na prática?

Senhores, eu vos apresento a classe Dispatcher, encarregada de interpretar as urls de nossa aplicação e executar os métodos apropriados nos controllers corretos. Ela também vai checar se o controller e o método requisitados realmente existem, e vai apresentar mensagens de erro em caso negativo. Por fim, a classe vai separar corretamente os parametros do request, enviando um array já certinho para o método que foi chamado.


Uma outra função muito interessante de nossa classe Dispatcher vai ser interpretar extensões; sim, amigos, vamos fazer com que a extensão definida na url defina o layout e o template a ser utilizado, seguindo uma estrutura de arquivos pré-determinada. Exemplo: se ao invés da url acima tivessemos alguma coisa como

http://nossoblog.com.br/blogpost/view/19.xml

Nosso framework, ao invés de utilizar o layout em /layouts/default/blogpost/view.php e o template /templates/default/blogpost/view.php utilizaria o layout /layouts/xml/blogpost/view.php e o template /templates/xml/blogpost/view.php. Deu pra sacar o poder? Assim vc pode criar outputs diferentes pra toda a sua aplicação sem nenhum estresse. Bonito demais. Pra colocar o sistema disponível em wap, bastaria fazer um layout e um template, no caso /templates/wml/view.php e /layouts/wml/view.php e utilizar os códigos wml ao invés de html dentro deles. Eu adoro isso.

Você acaba de perceber a beleza de uma solução MVC. A lógica fica totalmente separada da apresentação, o que faz com que seja fácil fazer apresentações totalmente diferentes com o mesmo conteúdo. Sweet!

Vamos então à descrição da classe?

Class Dispatcher


Propriedades

$url

String. Propriedade que irá conter a url requisitada.


$controller

Objeto do tipo Controller. Esta propriedade irá conter uma nova instância do controller requisitado. No nosso exemplo, BlogPost.

$method

String. Método a ser executado no controller requisitado. O método será view(), no nosso exemplo.


$parameters

Array com os parâmetros enviados na requisição via get ou post. No exemplo acima, ele teria uma entrada $parameters["default"]=>"19" já que não nomeamos este parâmetro no request. Poderíamos, se nós fossemos chatos, ter montado a url assim:

http://nossoblog.com.br/blogpost/view/id/19


e aí nosso array seria montado na forma $parameters["id"]=>"19"

O framework vai ser esperto o suficiente pra perceber quando temos só o valor ou o par nome/valor e vai resolver tudo isso pra nós.

Métodos


parseURL()

O método parseURL() interpreta uma URL segundo os padrões combinados e popula as propriedades do nosso Dispatcher. Na prática, ele vai separar os pedacinhos da url, dividindo a string em partes. Em primeiro lugar, ele remove a string relativa ao protocolo (http:// ou https://). Depois, o domínio. Ficamos então com a estrutura

controller/método/parametros.extensao

Aí fica facil separar tudo, não?


parseParams()
O método parseParams() faz o mesmo que a função acima, só que para os parâmetros enviados por get e post. Tudo o que estiver entre um ? e o ponto da extensão será considerado parâmetro get. Também será considerado parâmetro get tudo o que vier depois da action requisitada, no caso de nossos exemplos acima "19" e "id"=>"19". Tudo o que vier no $_POST vai ser incluído também em nosso array $parameters.

Repare que pra simplificar as coisas não vamos considerar a diferença entre get e post em nosso array $parameters; será igual fazer um request por get e post. Juntaremos tudo no array, sem distinção.

2007-11-22 01:44:13

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 20)

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 20)

Para ver os artigos anteriores desta série, clique aqui.

Olá pessoALL. Estamos aqui mais uma vez pra falar de Orientação a Objetos de um jeito bem prático, utilizando o pattern MVC para exemplificar conceitos importantes. A linguagem escolhida, você provavelmente já sabe, é PHP. Então sinta-se à vontade, sente mais perto da fogueira que já vamos começar nosso papo.

Chegamos a um momento importante de nossa série. Vamos falar hoje do último vértice da tríade MVC, mais especificamente a classe View. Você lembra que deixamos a classe View por último por se tratar do conceito mais simples dos três? Muito bem, chegou a hora de ver se a coisa é tão simples quanto falamos.

Nossa classe base View terá a responsabilidade de imprimir nossas páginas HTML, juntando o conteúdo dinâmico obtido por nossos Controllers ao código que colocamos nos templates que criamos. Portanto, primeiro precisamos definir direitinho o que é um template dentro de nosso framework, já que existem inúmeras definições por aí.

Nossos templates serão páginas php especiais, contendo basicamente html, que vão ser utilizadas por nossa classe View para imprimir as páginas de nossas aplicações MVC na tela. Normalmente nestes templates vão conter todo o html básico da página e comandos PHP para imprimir as informações dinâmicas provenientes do controller, normalmente usando só algumas poucas funções do PHP como echo, print e foreach.

Um exemplo de template talvez deixe isso tudo mais claro. Imagine que já temos tudo pronto em nosso sistema de gerenciamento de blogs, e chegou a hora de fazer o template que mostra um post. O código deste template (muito simplificado, claro) seria algo assim:
<h1><?php echo $this->data['BlogPost']['title'] ?></h1>
<div class="post"><?php echo $this->data['BlogPost']['text'] ?>
</div>

Reparem que não precisamos incluir no template nenhuma informação de tipo de documento (DOCTYPE) ou mesmo a seção <head>. Nossa classe View vai colocar tudo isso automaticamente pra nós, de acordo com definições gerais que vamos colocar em outros arquivos, chamados de layouts. Os layouts são basicamente arquivos HTML sem a seção <body> do html, e servem justamente para que não precisemos ficar repetindo estas informações toda hora. A classe View vai combinar layouts e templates para construir a página. De forma simplificada, portanto, podemos dizer que nossos templates são o corpo do documento html (<body>), e os layouts são o resto. Deu pra sacar?

O que os templates têm de especial? Nada, sinceramente. Especial é o acordo que fazemos para só utilizar html e funções de apresentação dentro deles. Isso é fundamental para que não misturemos lógica (que deve estar toda no controller) e apresentação (que deve estar toda no template). Se você começar a usar outras funções que não echo, print ou foreach (ou alguma outra função de formatação, tipo printf ou number_format) dentro dos templates você vai voltar imediatamente pro inferno.

Alguns caras levaram isso tão a sério que chegaram a criar linguagens especiais só para não usar PHP dentro dos templates. O Smarty, um dos mais poderosos sistemas de template já escritos em php, faz exatamente isso.  Eles criaram tags especiais para cada uma das funções PHP de apresentação, além de terem bolado uma série de outras interessantes. Ao invés de escrever algo tipo


<h1><?php echo $nome ?></h1>


no Smarty você escreveria

 

<h1>{$nome}</h1>

Bem interessante, não? Isso força o programador a utilizar somente os comandos do Smarty, que são somente de apresentação.

Mas veja que desenvolver uma solução como essa dá bastante trabalho: no fundo, toda essa codificação especial precisa ser transformada novamente em PHP alguma hora. Os críticos dizem que isso é desnecessário e prejudica a performance, já que o PHP oferece todas essas funções nativamente. Bem, os caras do Smarty (e de outros template engines que existem por aí) contra-atacam dizendo que todos os templates são compilados e cacheados em PHP, de forma que a diferença de performance é mínima.

Nós não temos aqui a pretensão de escrever um Smarty; o caminho mais simples é usar PHP puro. Este, portanto, é o caminho que vamos seguir.

Vamos à nossa descrição genérica da classe View:

Class View
Propriedades

$data

Array associativo contendo todas as informações dinâmicas de modelos e coleções.

$url

String com a url que está sendo acessada.

$layout

String com o nome do layout a ser utilizado. O Default é nulo, o que irá fazer com que a classe View utilize um layout padrão.

$baseurl

String com a url base do site para facilitar a montagem de links e caminhos de arquivos.

 $variables

Array associativo que pode conter outras variaveis genéricas definidas pelo controller.

 

Métodos

render($action,$layout)

Imprime a ação $action usando o layout $layout. Os defaults são a ação corrente e o layout default.

setVariable($variablename,$value)

Define uma variável para uso no view.

setPageTitle

Define o título da página a ser impressa (na tag <title>)

renderError($error)

Imprime uma página de erro utilizando o layout default para erros.

 


2007-11-13 02:37:51

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 19)

Para ver os artigos anteriores desta série, clique aqui.

Muito bem, caros amigos, voltamos à série que explica os conceitos transcendentais de programação orientada a objetos numa linguagem que todos podem facilmente entender. Este seu autor agradece novamente a todos pelos e-mails e comentários, são eles que nos incentivam a continuar sempre.

No último capítulo começamos a descrever nossas classes, notadamente a classe base Model, de fundamental importância em nosso quase-framework MVC. A fim de continuar nossa tarefa, proponho uma pequena reorganização de nosso estimado acrônimo: gostaria de falar neste artigo da classe base Controller, antes de falar da classe View. O motivo é simples: acredito que vai facilitar o entendimento se deixarmos para falar da classe View depois. Como o PHP é praticamente uma linguagem de construção de templates, posso afirmar de forma geral que todos que já trabalharam com PHP vão entender mais facilmente o conceito de Views.

Vamos lá, então? Vocês ainda se lembram do artigo no qual falamos que a url requisitada para o browser iria definir os modelos e ações a serem realizadas? Muito bem, só pra lembrar, nossas urls terão o seguinte formato:

http://www.meusite.com.br/modelo/acao/parametros

Nosso controller, então, vai saber direitinho em qual modelo aplicar uma determinada ação com certos parâmetros. Um exemplo seria:

http://www.meublog.com.br/blogposts/add/

Nesse caso, primeiramente nosso controller iria instanciar um objeto da classe BlogPost, que é filha da classe Model e já herdou tudo o que precisa para fazer as operações no banco de dados.

Repare que para facilitar vamos utilizar sempre o nome dos controllers no plural - alguns de vocês devem ter estranhado o fato de um controller BlogPostS instanciar na verdade um objeto da classe BlogPost (sem o S). O motivo é bem simples: o controller BlogPosts irá cuidar tanto da criação/edição/visualização/exclusão de um único BlogPost quanto da visualização de coleções de BlogPosts. Quando trabalhamos com um único registro, um único artigo de nosso blog, ele irá utilizar a classe BlogPost. Quando precisarmos trabalhar com coleções ou listas de artigos, como por exemplo uma listagem paginada, ele irá utilizar a classe BlogPostCollection.

Bom, vamos continuar: em seguida, nosso controller de BlogPosts iria executar seu método add. Este método iria checar se existe algum post http de formulário de dados do usuário.

Em caso negativo, ele instancia um objeto da classe View e imprime o template adequado, que claramente será um formulário que submete seus dados para a mesma URL,

http://www.meublog.com.br/blogposts/add

O template adequado, nesse caso, é o arquivo add.tpl, que fica dentro de uma pasta BlogPosts, que por sua vez vai ficar dentro de uma outra pasta Views, em um lugar seguro de nosso servidor que não precisa nem estar disponível publicamente. Repararam como até mesmo a organização dos arquivos é bem resolvida dentro de um framework? Só precisamos criar templates com os mesmos nomes que nossas ações e colocá-los nos folders com os mesmos nomes de nossos controllers para que a mágica aconteça.

Bom, imaginando que o usuário tenha preenchido o formulário acima e o tenha submetido, nosso controller recebe os dados, popula o objeto instanciado da classe BlogPost que está na propriedade $model com os dados que vieram do formulário, faz a validação executando o método $model->validate() e se estiver tudo bem, salva os dados executando $model->save() e mostra uma mensagem de sucesso usando o método flash(). Esse método imprime uma mensagem na tela durante alguns segundos e em seguida redireciona o usuário para outra página qualquer, no nosso caso provavelmente a lista de posts.

Deu pra entender?

Class Controller

Propriedades

$model

A propriedade $model vai armazenar o modelo no qual nosso controller irá operar as ações desejadas. Em nosso exemplo, ele armazenaria uma instância da classe BlogPost.

$modelcollection

A propriedade $modelcollection vai armazenar uma instancia da coleção relacionada ao modelo requisitado a fim de fazer as operações com coleções ou listas. No nosso caso, uma instância da classe BlogPostCollection.

$action

$action vai guardar a ação solicitada. No nosso exemplo, add. Para que a mágica funcione, nosso controller deverá ter um método add(). Para cada ação deverá existir um método correspondente em nosso controller; ações que não existem serão tratadas como erro.

$parameters

A propriedade $parameters guarda todos os parâmetros extras do request. Por exemplo, se estivéssemos vendo uma lista de Posts, poderíamos usar paginação, e o número da página viria como um parâmetro:

http://www.meublog.com.br/posts/list/page=3

$othermodels

$othermodels é uma propriedade que vai nos permitir instanciar objetos de outros modelos que não somente os da classe requisitada no request. Por exemplo, poderíamos querer utilizar as informações do usuário que está adicionando o post a fim de gravar no banco quem fez a última alteração. Assim, precisaríamos também de um objeto da classe User.

$view

Instancia da classe View que irá imprimir na tela os templates correspondentes.

 

Métodos

flash($message,$url,$seconds)

O método flash() mostra o texto de $message durante alguns segundos ($seconds) e em seguida redireciona para a url especificada. Muito útil para mostrar uma mensagem de sucesso ou fracasso de alguma ação.

redirect($url)

O método redirect() é muito simples: ele simplesmente redireciona o processamento para a url desejada.

Por hoje é só, pessoal. Voltamos a qualquer momento com mais orientação a objetos para vocês!

 

 

2007-10-09 04:59:38

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 18)

Para ver os artigos anteriores desta série, clique aqui.

Olá Pessoal, estamos de volta com a série que mostra alguns princípios de programação orientada a objetos precisamente a cada rand (1,32768) dias!

Muito bem, senhoras e senhores. Acho que chegou a hora da gente "objetivar" um pouco e listar aqui nossas classes e seus métodos: até eu, depois de algum tempo sem escrever, me perdi! Já falamos livremente sobre os modelos, controllers e views de nosso quase-framework; agora é importante colocar no papel. Digo, no banco de dados. Enfim, vocês entenderam.

Então vamos começar com a classe Model, base para todos os nossos modelos:

Classe Model

Atributos 

$primarykey

String. Nome da chave primária do banco de dados. O default é id, mas pode ser qualquer nome desde que seja inicializado ao criar o modelo.

$table

String. Nome da tabela à qual o modelo será mapeado. O default é o nome do modelo.

$data

Array. O array $data vai conter os dados do modelo, mapeando cada campo com seu valor.

$fields

Array. Lista dos campos da tabela relacionada ao modelo, associado ao tipo e tamanho de cada campo. O default é obtido diretamente do banco de dados.

$validationstatus

Array. O array $validationstatus contém a situação de validação de cada campo do modelo. O método Validate() popula este array com a situação de cada um dos campos, (true/false) de acordo com as regras de validação de cada um.

 

Métodos

LoadById($id)

Carrega os dados do registro cuja chave primária é $id no array $data do modelo.

Save()

Salva os dados do modelo no banco. Antes executa a função ValidateFields() para garantir que os dados são válidos. Se a chave primária no modelo estiver vazia, ele cria um novo registro. Se estiver preenchida, ele atualiza os dados do registro que contém este id.

DeleteById($id)

Remove da tabela o registro com o id $id. Bem simples. O único perigo aqui é se a gente não configurar corretamente a tabela para lidar com o efeito cascata, ou seja, se a gente deixar alguém apagar um registro que é referenciado por outros registros. Por exemplo, se eu apago um post que tem vários comentários relacionados, precisamos remover todos eles, certo? A boa notícia, pra quem ainda não sabe, é que o banco cuida disso sozinho pra nós.

ValidateFields()

Valida cada um dos campos de acordo com suas regras de validação. Como a classe Model é uma classe genérica, ou melhor dizendo, abstrata, vamos fazer aqui uma validação também genérica, de acordo com as características dos campos da tabela. Assim, vamos validar, por exemplo, se um determinado campo é texto, e se seu tamanho está dentro do tamanho estipulado na descrição da tabela. Para validações mais específicas, vamos reescrever a função ValidateFields() em cada um dos nossos modelos.

Reparem, caros leitores, que nosso objetivo aqui é clareza e simplicidade. Poderiamos ter chamado a função LoadById simplesmente de Load; Mas a idéia é deixar o uso da função realmente claro; Percebam que já na função Save isso já não é necessário pois vamos salvar o estado do modelo no banco, sem a necessidade de nenhum campo específico estar definido. Para salvar um novo registro vamos simplesmente salvar um modelo que tenha sua variável $id vazia.

Uma diferença bastante grande desta proposta em relação ao Cake é a divisão de trabalho: como o Cake usa o pattern ActiveRecord, tem muita coisa dentro da classe Model. Aqui nós estamos dividindo este trabalho com a classe ModelCollection, que irá fazer todo o trabalho de banco de dados quando estivermos lidando com grupos de registros, ou coleções.

That's all, Folks! Mandem seus comentários, dúvidas e xingamentos e até a próxima!

 

2007-07-03 04:58:16

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 17)

Para ver os artigos anteriores desta série, clique aqui.

Olá pessoal. Obrigado por todos os comentários e emails! Estou tendo um prazer enorme escrevendo essa série, e fico ainda mais feliz quando vejo que realmente tem gente curtindo.

Mas vamos ao que realmente interessa. No nosso último encontro expliquei que existem diferentes formas, ou patterns, para lidar com buscas e coleções de objetos, mas que eu ainda não estava satisfeito com aquilo que conheço. Como já disse em outras oportunidades, aprendi o pouco que sei de PHP nos becos escuros da internet, entre latões de lixo e scripts procedurais escritos por sabe-se lá quem. Não tenho, portanto, nenhuma pretensão de conhecer todos os sutras da programação orientada a objetos. Mas, outro dia, eu tive uma idéia que achei interessante, nada original, mas um pouco diferente das duas implementações que mostrei pra vocês.

Um dos design patterns mais interessantes (e, para mim, mais difíceis de entender) que conheço chama-se Iterator. Devo ter lido as definições e exemplos umas 1000 vezes sem entender direito como usar essa coisa. Pra quem vem de um passado procedural, especialmente usando uma linguagem como o PHP que lida muito bem com arrays, é muito difícil entender o benefício de usar os tais iterators.

Os iterators, juntamente com um outro pattern chamado Collection, vão formar a base do nosso novo desenho. O que estou pensando é relativamente simples: assim como temos a classe base Model, para operações com modelos, quero criar uma classe ModelCollection, que vai cuidar das operações com coleções de modelos. Dessa forma, temos um paralelo interessante: assim como podemos carregar as informações do modelo fazendo $model->load e assim por diante, poderemos carregar as informações de coleções fazendo $modelcollection->load.

O que eu gosto nesse desenho é que tudo fica claramente definido: um $model é sempre um objeto, enquanto que os $modelcollections são sempre coleções de objetos. Uma função de um $model jamais vai retornar uma coleção de objetos; uma $modelcollection jamais vai retornar um objeto (caso uma busca retorne apenas um resultado, ainda assim será uma coleção com apenas um objeto).

Parêntesis: uma das coisas que me deixa maluco no PHP é o fato de você poder misturar absolutamente tudo - uma mesma função pode retornar uma string, um array, um objeto... É o que os estudiosos chamam de loosely typed language, uma linguagem que não exige a definição dos dados usados pelas variáveis. Claro que essa característica pode ser usada para o bem: muitas implementações interessantes usam essa característica para flexibilizar e agilizar o desenvolvimento. Mas com o tempo, depois de passar anos da minha vida tentando decifrar códigos de scripts PHP por aí, eu afirmo categoricamente: tentar entender um script ou classe de alguma outra pessoa escrita em uma linguagem loosely typed é muito mais difícil.

Mas por que esse parêntesis tão grande? Porque no desenho que estou propondo vamos sempre lidar com objetos; Porque as Collections nos oferecem possibilidades muito, mas muito interessantes mesmo pra trabalhar com objetos e coleções de classes diferentes de forma transparente.

Não entendeu? Bom, vamos aos nossos exemplos então. Imagine que temos dois modelos completamente diferentes. Tipo "Post" e "Carro". Logicamente, dentro do nosso desenho, vamos ter os modelos $post e $carro, além das collections $postcollection e $carrocollection. Onde queremos chegar? Bem, como tanto a classe PostCollection quanto a classe CarroCollection são "filhas" da classe ModelCollection temos a certeza que estas subclasses implementam as mesmas funções. E por que isso é lindo? Porque eu posso agora implementar, por exemplo, a classe HtmlHelper, cuja função buildTable aceita qualquer ModelCollection e imprime uma tabela html. Pra usar, basta fazer $htmlhelper>buildTable($postcollection) ou $htmlhelper->buildTable($carrocollection).

Sacaram a beleza? Esse é só um exemplo do que podemos fazer com as collections e os iterators, mas o importante é ver que esse design faz com que qualquer coleção se comporte de forma igual, pra que a gente possa implementar coisas genéricas que funcionam pra qualquer uma delas. A coisa que imediatamente vêm à mente é que essa classe ModelCollection vai ter um método genérico pra fazer paginação, um pra fazer ordenação dos dados, e assim por diante.

Quando nossas classes estiverem prontas, olha só o que vamos precisar fazer pra imprimir uma tabela html:

(controller)

/* A função ModelController::loadPage() carrega a página indicada no $_GET['page'] e no $_GET['pagesize']

já na ordem indicada por $_GET['orderby'] e $_GET['direction'] */

$this->postcollection->loadPage();

(view)

$htmlhelper->buildTable($postcollection); // imprime a tabela

$htmlhelper->createPreviousPageLink($postcollection); //cria o link para a próxima página

$htmlhelper->createNextPageLink($postcollection); //cria o link para a próxima página

E acabou. Não é legal isso?

Até a próxima!

2007-06-05 04:32:35

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 16)

Para ver os artigos anteriores desta série, clique aqui.

Olá amigos, estamos de volta. Semana de muitas emoções pra quem gosta de Tênis: Roland Garros é sempre uma festa. Este seu humilde autor confessa que, em sua tenra juventude, chegou a disputar alguns torneios; Lembro-me claramente de ganhar uma cesta com catchup, mostarda, mini-pepinos, azeitonas e mais alguns outros enlatados da empresa patrocinadora de um dos torneios de que participei. Minha melhor colocação, 3o colocado. Pensando bem, acho que fiz bem em não seguir a carreira.

Mas, deixando Jankovics, Vaidisovas, Sharapovas e Ivanovics de lado por alguns momentos, quero voltar nossa atenção novamente para os modelos do MVC. Muito bem amigos, hoje vamos tentar definir o que todos os nossos modelos devem minimamente fazer. Nosso objetivo hoje é listar os métodos da nossa classe Model, a classe base para todos os modelos que criarmos. Não tenho a pretensão de fazer um estudo teórico detalhado; dentro de nossa filosofia PHP de Rua® o que estamos buscando é somente o básico, o essencial.

Então, caros amigos, quais seriam estas funções essenciais, compartilhadas por todos os modelos que vamos criar? Lembrando nossas conversas anteriores, o modelo é um ajudante, uma classe que só existe para ler e gravar informações em nosso banco de dados, e sua estrutura de dados será sempre mapeada à estrutura de uma tabela que existe no BD.

Por exemplo, se criarmos um modelo Tenista, que possua as variáveis $id$nome$ranking, é certo que teremos uma tabela que guardará esta informação, que pra facilitar (nomes têm poder, lembrem-se disso) chamaremos de Tenistas. Essa tabela terá, minimamente, os campos id, nome e ranking. Sacou?

Estamos, de fato, mapeando uma classe à uma tabela, e instâncias da classe a registros da tabela. Essa técnica é chamada de ORM, Object-Relational Mapping. A coisa é mais interessante ainda: como estamos falando de OOP, em algum de nossos métodos vamos bolar um jeito de fazer esse mapeamento da forma mais simples e genérica possível, pra que não tenhamos que criar queries sql específicas para cada novo modelo que criamos.

Vejam a beleza dessa solução, caros leitores! Quando terminarmos a classe Model, qualquer novo objeto de uma classe que a estenda poderá ser salvo ou lido direto do banco sem precisar que nós façamos uma query específica!

Sendo assim, creio que já ficou bastante claro que precisamos das funções save() e load() em nosso modelo-base. A gente não precisa gastar muitos neurônios pra perceber que também precisamos da função delete() além da função __construct() que todos as classes já nos oferecem para criar novos objetos.

Nesse ponto começa uma saudável polêmica: onde devem ficar as funções para buscar objetos? Se eu quiser pegar todas as tenistas que estão no banco, pra quem eu devo pedir? Em alguns frameworks MVC, como o CakePHP, estas funções ficam na classe Model mesmo. Então vocë encontra funções como findAll(), findById(), findByName() e coisas assim, dentro da classe Model.

Pra ser muito sincero, eu acho meio esquisito pedir pra uma tenista buscar as outras tenistas. É assim que fica no CakePHP:

$tenista = new Tenista();

$todasastenistas = $tenista->findAll();

Cara, eu acho isso muito esquisito. A semantica da coisa, sabe? Acho que é um pouco de preciosismo, eu sei. Adoro o Cake, estou realmente impressionado com sua facilidade de uso, mas acho o design da classe model um pouco confusa.

Outros frameworks e ORMs fazem diferente. Criam uma classe só pra fazer isso. Um gnomo, lembram-se? Então, o cara faz o seguinte:

$gnomo = new DbManager();

$todasastenistas = $gnomo->findAll('tenista');

 Nesse caso, a classe DbManager tem todos os tais métodos pra retornar arrays buscados no banco. Hm. Acho um pouco melhor, mas ainda acho estranho não termos uma classe mais esperta, que possamos estender para criar comportamentos diferentes caso a gente precise. A resposta está próxima, caros amigos. Mas não posso perder a chance de continuar no próximo capítulo, não é mesmo?

Até a próxima.

2007-05-02 05:25:23

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 15)

Para ver os artigos anteriores desta série, clique aqui.

Olá meus caros. De volta. "Que você viva em tempos interessantes". Esta antiga maldição chinesa (!?) explica muito bem a sensação que toma conta deste seu humilde autor. Muito a fazer, muito a compreender, pouco tempo. Desculpas à parte, retorno à esta série para falar mais um pouco sobre Exceptions, um conceito fundamental que talvez ajude alguns de vocês a poupar um tanto desse tão precioso tempo; afinal, como bem disse Benjamin Franklin, o tempo perdido nunca mais será encontrado.

Muito bem, senhores, o que faz nossas Exceptions tão especiais? Para entender, precisamos pensar na forma como gerenciamos erros em nossas aplicações. Ou melhor, precisamos pensar na forma como lidamos com erros em nossas vidas. Talvez isso complique as coisas, mas falar sobre a vida sempre é mais interessante, não?

Joãozinho trabalha numa fábrica de automóveis. (é um exemplo, ok? Não quero entrar em discussões morais sobre trabalho infantil, capitalismo, revolução industrial, etc e tal. Tudo bem, é um exemplo estúpido. Podemos ir em frente?) Joãozinho aperta parafusos na linha de montagem, e sua supervisora é a Mariazinha. O chefe da Mariazinha é o Aristides, que fica lá em cima no escritório.

Bom, você sabe que numa fábrica todo tipo de problema pode acontecer. Alguém pode esquecer de mandar o parafuso para o Joãozinho, o parafuso que foi mandado pode estar com defeito, o próprio Joãozinho pode vacilar e não apertar o parafuso... Sabe lá o que pode acontecer. Diante desse cenário, como você faz para gerenciar todos os erros que podem acontecer? Dá uma lista de IFs infinita para o Joãozinho para que ele mesmo resolva tudo? "Se o parafuso estiver com defeito, corra até a sala do Aristides e aperte o botão para parar as máquinas". "Se você dormir no ponto e não apertar o parafuso, corra até a sala do Aristides e aperte o botão para parar as máquinas", e assim por diante? Hmm... não sei se vocês estão entendendo, mas já está dando preguiça só de pensar em fazer essa lista. E a preguiça, amigos, é o nosso sentido-aranha, é nosso superpoder psiônico que avisa quando alguma coisa está esquisita no ar. Imagina se a Mariazinha tiver 50 funcionários sob sua supervisão, vai ter gente correndo pra tudo o que é lado, a sala do Aristides vai ficar totalmente destruída, e produção que é bom nada.

Apresento-lhes, então, as Exceptions, e seus companheiros inseparáveis Try, Catch e Throw. Vamos olhar para o problema acima de um outro ângulo. Imagine se a gente pudesse dizer o seguinte pro pessoal da fábrica:

Olha, Joãozinho, você vai tentar apertar o parafuso. Qualquer problema que você tiver, escreve num papel, amassa até virar uma bola e arremessa pra Mariazinha. A Mariazinha pega a bola, e se não for um problema que ela saiba resolver, amassa de novo e arremessa pro Aristides. Se ele também não souber resolver, a gente para a linha de produção na hora.

Tentar... Pegar... Arremessar... Vocês... sacaram? (se você viu Warriors, na versão legendada, está rolando no chão de rir nesse momento). [Agora relendo esse artigo me parece claro que o criador deste conceito gostava muito de baseball, ou cricket] Se vocês ainda não sacaram, vamos escrever um pouco de (pseudo)código:

/*
* Created on 02/05/2007
*
*/

class Apertador {

    function apertarParafuso(){

        echo "parafuso apertado!";

    }

    function oopa($descricao){

        echo "Apertador: oopa! Deu pau! Segura aí supervisor!";
        throw new Exception($descricao); // amassa e joga a bolinha pra cima!

    }

}



class Supervisor{

    function mandaApertar(){

        try {

            $joaozinho = new Apertador();

            $joaozinho->apertarParafuso();

            $joaozinho->oopa("Parafuso com defeito");

        }

        catch (Exception $e){
            echo "Supervisor: xi! Exception! Não sei o que fazer! Toma aí chefe!";
            throw $e; // peguei a bolinha, mas não sei o que fazer com ela... manda pra cima!

        }

    }

}



class Chefe{

    function vamosTrabalhar(){

        try {

        $mariazinha = new Supervisor();

        $mariazinha->mandaApertar();

        } catch (Exception $e) {
            
            echo "Chefe: Para tudo! Quero saber o que aconteceu aqui!"
		echo $e;
            die("Parando as máquinas!");

        }

    }

}


// Muito bem, agora a gente contrata o Aristides:


$aristides = new Chefe();

$aristides->vamosTrabalhar();

?>

 

Rode esse script e veja o resultado. Que interessante! Basta o Joãozinho mandar o erro pra cima que todos na cadeia (as classes que chamam a classe Apertador, neste caso) recebam aquela Exception, graças ao uso do comando Try. Tudo o que roda dentro de um bloco Try é monitorado, e caso uma Exception seja "jogada" ou "arremessada" pra cima o controle vai para o bloco Catch imediatamente abaixo.

Perceba também que ao gerarmos uma Exception, ela já é criada com um monte de informações importantes automaticamente: em qual arquivo e linha que o erro aconteceu, um Trace completo passando por todo o código até o Catch que "pegou" aquela Exception e muito mais. Para ver um bom resumo, basta mandar imprimir a variável que contém a Exception; mas você também pode acessar as propriedades do objeto separadamente usando métodos como $e->getMessage(), $e->getLine(), $e->getFile() entre outras. Não é bom isso?

Com as exceptions nosso trabalho passa a ser somente colocar os Throws nos locais onde erros acontecem, deixando o tratamento desses erros para classes mais acima na hierarquia. Mesmo que você não trate estas Exceptions com blocos Try/Catch a coisa funciona: você pode deixar a exception subir na hierarquia até chegar ao topo, pois toda exception que chega ao topo sem ser "pega" gera um erro fatal. Então, caros amigos, vocês podem trabalhar inicialmente só colocando throws no código, e, ao final, refinar o tratamento distribuindo blocos try/catch pelas classes da hierarquia. Muito bonito.

Mas tem uma coisa ainda mais bonita. Sim, amigos, a classe Exception pode ser estendida. É uma classe como outra qualquer. Isso quer dizer que no nosso caso você poderia criar a exception DefeitoParafusoException, que já conteria a mensagem de erro e mais outras informações que você necessita sem precisar nunca mais digitar. Exemplo:

 

class DefeitoParafusoException extends Exception {
     function __construct(){
        parent::__construct();
        $this->message = "Defeito no parafuso!";
    } 
} 

 

Sacaram? Agora toda vez que você criar uma nova Exception do tipo DefeitoParafusoException a mensagem já será colocada por default na variável $this->message da Exception em questão! Imagine o que você pode fazer com isso. Mas ainda tem mais. Imagine agora que você não quer parar a produção simplesmente por causa de um parafuso com defeito. Muito bem, então vamos fazer com que os Supervisores comecem a "Pegar" este tipo de Exception para não incomodar o chefe:

 

 class Supervisor{

    function mandaApertar(){

        try {

            $joaozinho = new Apertador();

            $joaozinho->apertarParafuso();

            $joaozinho->oopa("Parafuso com defeito");

        }

        catch (DefeitoParafusoException $e){
            echo "Supervisor: é só um maldito parafusinho, diabos! Continuem!";
        }
        
        catch (Exception $e){
            echo "Supervisor: xi! Exception! Não sei o que fazer! Toma aí chefe!";
            throw $e; // peguei a bolinha, mas não sei o que fazer com ela... manda pra cima!

        }

    }

}

 

pra ver isso funcionando, precisamos alterar a função Apertador::oopa() para mandar uma DefeitoParafusoException:

 

 function oopa(){

        echo "Apertador: oopa! Deu pau! Segura aí supervisor!";
        throw new DefeitoParafusoException(); // não precisa mais da descrição...
} 

 

E pronto. Vocês perceberam que podemos utilizar vários blocos de catch um embaixo do outro? Essa é a beleza desta solução. Podemos começar com um tratamento de erros bem genérico, e depois ir especializando com novas subclasses, sempre lembrando de colocar as subclasses mais específicas, neste caso a DefeitoParafusoException nos blocos anteriores, deixando o catch genérico (Exception $e) por último.

Por hoje é só, pessoal, dúvidas, reclamações, elogios e doações são bem-vindas. Grande abraço a todos.

 

2007-03-04 03:21:08

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 14)

Para ver os artigos anteriores desta série, clique aqui.

Estamos de volta, caríssimos leitores. Mais uma vez agradeço pelos comentários e emails. No último artigo nós fechamos o conceito de controllers, e vimos alguns exemplos práticos de como usá-los. Nos artigos anteriores, definimos as outras partes do MVC, models e views (ou templates). Tudo isso sem escrever uma só linha de código.

Bem, depois de tanto tempo sem digitar um único if, alguns de vocês começam a manifestar uma patologia cientificamente conhecida como "fome de código", ou "Síndrome da abstinência de programação". Os sintomas são variados: suor nas mãos, digitação de códigos procedurais aleatórios, criação randômica de scripts, e, nos estágios mais avançados da doença, envio de emails e comentários para o site deste autor bradando palavras de ordem "Código! Queremos código!".

Para todos que estão desesperados para colocar a mão na massa, uma pequena história Zen talvez ajude a acalmar o espírito:

"Um monge perguntou a seu mestre:

– Mestre, quanto tempo vai demorar para que eu atinja a iluminação?

O mestre respondeu:

– Dez anos.

O discípulo respondeu, agitado:

– Mas e se eu trabalhar duro, estudar todos os sutras, praticar dez horas por dia, quanto tempo vai demorar?

– Nesse caso, respondeu o mestre, vai levar 20 anos."

Se existe uma coisa que é fundamental em OOP é paciência. É praticamente impossível fazer alguma coisa que funcione bem usando essa filosofia de trabalho simplesmente abrindo o seu editor e digitando código. Paciência, esse é o caminho.

Mas é necessário desenhar TODO o sistema, cada detalhe, cada vírgula? Certamente não. Mas como saber qual é o momento de parar de desenhar e começar a programar de fato? Ah, jovem monge, nós saberemos. Acredite, nós saberemos. Chegará a hora em que não teremos mais dúvidas, que vamos olhar nosso desenho do sistema e vamos dizer "é, acho que agora já dá pra começar". Ao longo dos anos muitas metodologias e processos foram criadas para tentar desvendar este mistério. Mas só o próprio desenvolvedor, em seu íntimo, sabe quando está pronto. Por mais documentação que um sistema já possua, por mais discussões que se tenha, por mais diagramas e casos de uso e o que for, sempre existe o momento da iluminação, quando tudo aquilo a que fomos submetidos simplesmente "clica" e começa a fazer sentido. Todas as nossas questões sobre como o sistema funciona começam a ser respondidas claramente, e não há mais nenhuma pulga atrás de nossas orelhas.

É, talvez essa seja uma boa definição: a hora de começar a programar é a hora em que não encontramos nenhuma pulga atrás de nossas orelhas. E nesse momento, ainda tenho algumas quando penso em nosso Digitalminds Blogging Engine. Por exemplo: Já sabemos quais são as classes principais que vamos usar, e como vamos usá-las. Mas ainda não sabemos quais métodos e variáveis elas vão apresentar. Qual a vantagem de termos as superclasses Model, View e Controller se não encontrarmos métodos e variáveis que efetivamente facilitem nosso trabalho de criar um sistema? Isso, caros leitores, é precisamente o que vamos fazer nos próximos artigos. Mas ainda nesse artigo quero tentar responder a uma outra questão que está na minha cabeça: Será que não precisamos de mais nenhuma classe nessa história toda?

Bom, eu sempre costumo dizer que a preguiça é uma das minhas grandes virtudes; ela já me ajudou a resolver inúmeros problemas e a ganhar muito tempo pra fazer o que realmente importa na vida, ou seja, nada. De qualquer modo, o que quero dizer com isso é que sim, acredito que teremos algumas outras classes nos ajudando a fazer coisas repetitivas ou chatas demais.

A primeira coisa que me vem à cabeça é "o que fazemos se um erro acontecer?". Sim, amigos, erros vão acontecer, e nós precisamos estar prontos para lidar com eles de uma forma civilizada. E quem já escreveu um sistema qualquer em linguagem procedural sabe como é chato fazer tratamento de erros. São tantas possibilidades, tantas combinações de erros, tantos ifs e tantos switches que só os mais corajosos acabam fazendo tratamento de erro de uma forma realmente completa.

Mas os criadores da programação orientada a objeto, em sua infinita sabedoria, olharam para nós mortais com piedade e com o som de mil trombetas bradaram "Que se criem as Exceptions!" E então, o mar turbulento do tratamento de erros se abriu, e o povo programador pôde passar em paz. Os criadores do PHP, em sua razoável e confusa sabedoria, olharam para nós, os loucos que usam essa linguagem idiossincrática, e também bradaram "Que se criem as Exceptions em PHP5!". E em um segundo, tudo o que já foi feito em PHP para tratamento de erros se tornou obsoleto e bizarro.

O conceito de Exception, senhores, é uma das coisas mais impressionantes que já foram criadas. E, como todo conceito mais complexo de OOP, é muito difícil de entender, justamente por ser uma coisa relativamente simples. Entendeu? Certamente não. Então fique ligado e não perca o próximo artigo.

Grande abraço pra todo mundo.

 

2007-02-12 13:34:41

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 13)

Para ver os artigos anteriores desta série, clique aqui.

Olá caros amigos caçadores de gnomos. Estamos de volta. Ainda precisamos fechar bem fechado este conceito fundamental chamado controller. Pegando do ponto onde paramos, que tal darmos alguns exemplos práticos de como nossos controllers vão funcionar? Gostou da idéia? Então entra aí e vamos lá.

Onde queremos chegar com toda essa conceituação? Bem, alguma coisa simples que torne o desenvolvimento e o uso de novas funcionalidades bem fácil. Vamos a alguns exemplos.

Primeiro, quero ver uma lista de posts simplesmente acessando a URL

http://meublog/posts/listar

Simples assim. Para criar um novo post:

http://meublog/posts/criar

Ah, e para ver um determinado post, o chamado permalink, quero acessar

http://meublog/posts/ver/xxxx

onde xxxx é o id do post, seja ele um texto ou um número.

Da mesma forma, para editar um post, quero acessar

http://meublog/posts/editar/xxxx

Para apagar um post

http://meublog/posts/apagar/xxxx

e assim por diante. Gostou? Muito bem, meu amigo, você acaba de definir o nosso primeiro controller, e suas primeiras funções ou métodos. Sim, veja a beleza da solução MVC, você está presenciando um mapeamento direto entre classes e métodos diretamente na url que o usuário acessa! Nas urls acima temos um controller chamado posts que tem 5 métodos: listar, criar, ver, editar e apagar.

Repare que ajuda bastante manter a coerência de linguagem - controllers normalmente são substantivos no plural (já que normalmente eles "controlam" dados de um modelo, no caso o controller "posts" lida com as informações do modelo "post") e os métodos normalmente são verbos. Alguns até chamam os métodos de "actions" ou ações, já que realmente nada mais são do que ações de fato. Capisce?

Bom, a essa altura já deve estar claro pra vocês (caso não esteja prometo que devolvo o dinheiro de volta) que já que temos dois modelos (posts e comentarios) precisamos, no mínimo, de dois gnomos: um pra cuidar de posts, e outro pra cuidar de comentários. Nasce, então, o controller "comentarios". Já sabem as urls e métodos que vamos ter que criar?

Por hoje é só. Até a próxima!

2007-02-04 06:11:55

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 12)

Para ver os artigos anteriores desta série, clique aqui.

E estamos de volta, amigos, em dia de Superbowl (você nem precisa gostar do esporte, mas assistir à final é quase uma obrigação. Os comerciais mais esperados do ano são exibidos durante o evento, o show do intervalo vai ser de Prince, e quem ainda não ouviu o comentarista da ESPN de futebol americano não sabe o que está perdendo - é a coisa mais engraçada da televisão brasileira). Mas nós não estamos aqui para falar de futebol americano, não é? Nosso assunto de hoje, isso sim, são gnomos!

Os gnomos, como todos sabemos, são criaturas lendárias que geralmente usam chapéus ponteagudos e barbas enormes. Presentes na mitologia européia e nos jardins de muitas pessoas de gosto duvidoso, nossos pequenos amigos têm a fama de ter poderes mágicos e de viajar pelo mundo.

Muito bem, caros leitores, chegou finalmente a hora de revelar a todos o porquê da presença desses furtivos seres em nossa história. O que têm em comum, afinal, os gnomos e a programação orientada a objeto?

(rufar de tambores) (trilha de "psicose") (silêncio absoluto)

A resposta é muito simples. Absolutamente nada.

Mas peraí! Peraí! Antes de pegar os ancinhos, enxadas e outras ferramentas agrícolas e se dirigirem até minha casa bradando "IMPOSTOR! IMPOSTOR! MORTE AO IMPOSTOR" preciso de algumas linhas para me explicar.

Dentro da minha filosofia "PHP de Rua®" procuro sempre usar metáforas para explicar alguns conceitos que considero mais complexos. Ok, algumas dessas metáforas não são tão interessantes assim, mas acho que algumas já ajudaram alguns de vocês a compreender um pouco mais do assunto em pauta. Os gnomos, meus caros, são mais uma dessas metáforas, como vocês já devem ter percebido.

A idéia de usar os gnomos me veio à cabeça quando comecei a entender melhor o conceito de "manager" em orientação a objeto. Muito bem, vamos recapitular um pouco pra lembrar alguns conceitos importantes. Todos se lembram que definimos classes para Automóveis, Seres Humanos, e outros objetos? Agora quero pedir que vocês procurem ver uma característica que todas essas classes têm em comum, do ponto de vista conceitual: todas elas são criadas a partir de objetos que, de um modo ou de outro, são coisas de verdade no mundo real. Um automóvel existe como "coisa" tanto abstratamente quanto concretamente. Não sei se vocês estão entendendo, mas talvez ajude dar um exemplo de alguma coisa que não exista na realidade para que fique mais claro.

Na nossa série temos focado em um tipo de modelagem chamada "Real World Modeling", ou modelagem do mundo real. Ou seja, sempre que falamos de classes e objetos, falamos de alguma coisa que efetivamente existe no "mundo real". Automóveis e Seres Humanos são exemplos disso. Poderíamos falar também de Registros (de um banco de dados) ou Fichas de Cadastro; mas sempre partimos de uma "coisa" que já existe na realidade, um conceito pré-existente. Sempre tive mais facilidade de entender este tipo de modelagem; é o que me parece mais lógico. Mas, como vamos ver, muitas vezes em programação orientada a objeto um sistema é modelado usando conceitos que não são reais, ou melhor dizendo, usando conceitos que são criados somente para o sistema que se está desenhando.

Os Controllers, peça fundamental do design pattern MVC, são justamente um exemplo deste problema. Explico: é fácil imaginar que um sistema de gerenciamento de blogs tenha as classes Post e Comment, pois no mundo real estes ítens são componentes de um blog. O conceito de Controller, no entanto, jamais apareceria se nós tentássemos encontrá-lo simplesmente olhando um blog. Trata-se de uma classe criada a partir de uma metáfora de uso criada especificamente para resolver um problema de programação. Na prática, estas classes são normalmente muito importantes em um sistema, e ao mesmo tempo são as mais difíceis de criar, já que não têm uma contrapartida no mundo real.

Mas muito bem, ok, já entendemos que os tais Controllers são diferentes dos outros objetos, mas o que eles são exatamente? Aha, aí é que está. Eles são gnomos, amigos. Criaturas imaginárias que fazem coisas pra nós. Eles recebem ordens e as executam, não recebem salário e não reclamam (bom, se a gente programa tudo certo eles não reclamam).

Os Controllers são fundamentais no modelo MVC, pois são os responsáveis por receber as ordens, ou requests, dos usuários do sistema, interpretá-las e mandar novas ordens para que outras classes executem seus métodos. Eles mandam no pedaço. São os reis da cocada preta. Os maiorais.

Muitos de vocês talvez já saibam que existem dois métodos muito importantes para se requisitar (request, sacou?) coisas quando no protocolo http. Eles são os superpoderosos GET e POST. O método GET pode ser visto na maioria dos sites, é só procurar uma url que tenha uma interrogação. Nesse tipo de request o pedido é feito na própria url, passando muitas vezes pares de variáveis separados por um & (e comercial). Um request GET típico seria:

http://www.google.com.br/search?q=oop

Este request, como vocês podem imaginar, está passando a variável "q" com o valor de "oop" para o sistema. Tudo bem simples e trivial.

Um request post é muito parecido. Na teoria, estes requests teriam funções diferentes, o primeiro para "pegar" informações do servidor e o segundo para "colocar" ou "postar" informações lá. Mas, na prática, essa regra não se aplica muito, a coisa é bem misturada. Para nós, essa distinção não é importante, e para um Controller de verdade ela também não deveria ser, já que queremos que esse gnomo entenda qualquer tipo de ordem que o usuário passe para ele.

Esse é exatamente o ponto. Um controller "recebe" ordens, ou requests e executa métodos de acordo. Ou seja, qualquer request que chege em nosso site irá ser tratado por um gnomo, ou Controller, que irá dizer para modelos e outras classes "ei, você, post número 25, apareça aqui que o usuário quer editá-lo!" ou "Ei template Lista de Posts, tome aqui esta lista de posts e desenhe-se na tela". Em um sistema que implementa autenticação de usuários, por exemplo, os Controllers perguntariam "Ei, autenticador, este cara aqui pode editar este post?" e coisas assim. Deu pra entender?

Até a próxima. Alguém aí já está se coçando pra escrever algum código? Calma, gafanhoto... Ainda temos que decidir que gnomos precisamos. Vejo vocês por aí. Grande abraço.

2007-01-08 02:09:46
tags: 

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 11)

Olá todo mundo. Estamos de volta depois de um final de ano chuvoso, marcado pelos excessos gastronômicos e pela total e absoluta imobilidade. Àqueles que conseguiram viajar, meus cumprimentos. A minha viagem vai ficar para o carnaval, não pude viajar desta vez. Acho que a melhor definição dessas "férias" de fim-de-ano foi "uma grande seqüência de sábados, seguida pelo maior domingo de todos os tempos". Mas, quem sou eu para reclamar! Deu pra descansar bastante, curtir um pouco e ganhar a Master League na dificuldade Professional duas vezes. 

No nosso último episódio falamos um pouco sobre Views,  a letra V do MVC. Pra quem está chegando agora, vale a pena dar uma olhadinha nos artigos anteriores. Hoje vamos falar de modelos. Um assunto muito mais interessante, não? Mas, calmaí. Antes que você se decepcione, não vamos falar de modelos, mas sim de modelos, ok?  

Bom, de forma bem simples, o M do MVC é o cara responsável pelo gerenciamento dos dados da aplicação. Toda vez que você precisar ler alguma coisa do banco de dados, ou atualizar alguma informação, você vai utilizar um modelo. A chave para entender os benefícios do MVC é perceber que cada uma das três partes faz um trabalho específico, o que torna tudo no final das contas mais simples e seguro.  Na implementação, normalmente se cria uma clase base (normalmente chamada model ou appmodel) que contém quase todas as variáveis e métodos que você precisa para acessar dados no banco. A partir dessa classe, outras classes são criadas, estendendo os métodos para cumprir funcões mais específicas para cada um dos tipos de informação.

A palavra "modelo" talvez seja um pouco difícil de entender. Acho que a tradução foi feita ao pé-da-letra pra manter o acrônimo MVC; mas eu sempre tive dificuldade de entender esse conceito, muito mais do que tive pra entender "View" e "Controller". Pra deixar o conceito mais claro na minha cabeça inventei uma metáfora, talvez ela ajude alguns de vocês. Penso em modelo como um modelo 3d, tipo um robozinho de computação gráfica, responsável por "buscar e levar" os dados até o banco. Assim quando a gente fala que vai criar um modelo para um Post, estamos na verdade construindo um robozinho chamado Post que irá realizar todas as operações com o banco, e guardar informações importantes para nos passar depois. Esse robozinho é criado a partir de um robô genérico, chamado Model, que contém todos os métodos genéricos de todos os robôs. Lembrem que como estamos no mundo da orientação a objeto, podemos criar, na verdade, vários robozinhos Post a partir da classe Post. Esses robôs são instâncias ou objetos da classe Post.

Aliás, pra coisas simples, vocês vão perceber que quase todas as funções ou métodos são muito similares para quase todas as informações. Essa é a beleza dos frameworks MVC como o Rails: só de instalar você já "ganha" uma série de métodos prontos pra usar. Mas essa é uma outra história, que vamos falar um pouco mais tarde.

Muito bem. Quais seriam os modelos que teremos que construir para nossa aplicação funcione? Alguém se arrisca? Vou pelo caminho mais simples, como bom preguiçoso que sou. O primeiro modelo, e mais óbvio, é o modelo de "Post". Sim, amigos, sem posts, não temos um blog. Concordam? Então vamos em frente. Que informações um post deve guardar? Essa é fácil: no mínimo temos que guardar o título do post, seu conteúdo e seu permalink. Pra poder identificar este post de uma forma simples, vamos guardar também uma identificação única, que pode ser um número, por exemplo.

Outro modelo importante pra nosso DBE é o modelo "Comment", que representa um comentário feito em um post. Os comentários vão  guardar o conteúdo do comentário e a identificação do post ao qual ele se refere.

Pra nossa primeira versão, que vai ser muito simples, acho que estes dois modelos serão suficientes. O que vocês acham? Ficou faltando alguma coisa?  Mandem seus comentários!

Grande abraço e até a próxima.

 

2006-12-17 07:20:18
tags: 

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 10)

Para ver os artigos anteriores desta série, clique aqui.

Olá todo mundo, escrever nesse calor que está aqui no Rio é quase uma insanidade, mas enquanto houverem leitores a série deve continuar! Hoje vamos começar a detalhar melhor nosso plano falando de uma das partes importantes que compõem o pattern MVC. Mais precisamente, o "V", ou View.

Decidi começar por aí (sei que parece estranho para quem já conhece o funcionamento do MVC) por uma razão bem simples: eu sou preguiçoso, e gosto sempre de começar pelo mais fácil. Na minha modestíssima opinião, o conceito de View é o mais simples dos três, e certamente o mais simples de implementar também.

Quem já trabalhou com algum template engine (como o Smarty, por exemplo), já conhece o conceito de View com outro nome: Template. Basicamente, uma View é um gabarito que permite a visualização de dados dinâmicos dentro de uma determinada formatação. Bom, na verdade é um pouco mais que isso, é também um conjunto de classes que suportam o uso destes templates, afinal se você simplesmente gravar um arquivo com html ele não vai se tornar dinâmico sozinho, não é mesmo?

Uma definição mais careta de View é a seguinte: "uma representação de um estado do modelo". Cuma? Bom, pensei numa metáfora razoavelmente idiota para explicar esse conceito, me perdoem se parecer meio ridículo, mas juro que estou fazendo o melhor que posso :-)

Primeiro, você vai precisar de um caderno, um lápis e um estilete. (?!) É isso mesmo. Vá lá no quarto e pegue um caderno, um lápis e um estilete. Se não tiver um estilete, nosso pseudo template não vai funcionar. Depois você vai entender por quê.

Arranque uma folha do caderno e escreva no topo "Template para criação de Posts". Esse será o nosso template 1. Logo abaixo, escreva "Título do Post:", e embaixo disso, "Texto do Post:". Tudo bem? Bom, você já tem um pseudo template html, mas ainda falta o fundamental, a conexão com o nosso pseudo banco de dados, também conhecido como caderno. O estilete, essa tão importante ferramenta, vai funcionar para fazer a conexão.

Pegue o estilete, e, ao lado do texto "Título do Post", faça um buraco (ou, em nosso pseudo html, um ítem de formulário Input Text) que permita mais ou menos 255 caracteres. Do lado de "Texto do Post:" abra um buraco ainda maior, simulando um TextArea. Eu falei que era uma metáfora meio idiota, não falei?

Muito bem, senhores, vocês têm em suas mãos um Template. Ou uma View, como queiram. Agora podemos usá-la tanto para escrever em nosso "banco de dados" quanto para visualizar seu conteúdo de forma bonita, formatada. Se quiser, você pode editar esse template pintando com hidrocor, sabe como é, dá pra fazer bastante coisa com Hidrocor Style Sheets. OK, deixa pra lá.

Para adicionar um "registro" no "banco de dados" basta "carregar" o seu template, colocando-o sobre uma página vazia do caderno, e escrevendo os dados dentro dos buracos no template. Para adicionar outro registro, vire a página e repita o procedimento. Nesse exemplo, o estado do modelo é a página que você está vendo. Mudar o estado do modelo, portanto, é como mudar de página nesse exemplo tosco. Vocês entenderam?

Claro que um modelo que não é feito de papel pode mudar de estado de outras formas, mudando quais informações estão disponíveis e a forma como elas estão sendo visualizadas. (Ainda preciso ver como fazer sort nesse banco de dados, mas ele possui a grande vantagem de ser portátil, de fácil utilização e ser facilmente expansível "conectando" outros "bancos de dados" quando o espaço acabar. Muito interessante, não? O chato é fazer backup.)

Bom, resumindo, uma View é uma espécie de gabarito que contém partes estáticas (escritas em html, no nosso caso) e outras dinâmicas (escritas em php simplificado, para garantir que não vamos colocar lógica dentro de nossos templates). Claro que os templates que vamos construir são mais poderosos e flexíveis que os feitos em PHTML ou Pseudo Html ou Papel html, sei lá.

Vou dar um exemplo: nosso blog, claro, vai disponibilizar um feed RSS para seus leitores. Usando templates, isso é muito simples: pegamos as mesmas informações que mostramos no blog usando um template bonitinho em html e as mostramos usando um template escrito em XML, no formato Atom, por exemplo. Pra isso funcionar, é só fazer um novo template trocando, por exemplo, a tag "h1" usada no html por uma tag "title", usada no formato Atom. Muito mais fácil do que ficar copiando queries, scripts inteiros, e coisas do gênero.

Em termos práticos, pra nós uma View vai ser um arquivo php que praticamente só contém html. As únicas coisas que estarão escritas em PHP serão os dados que vêm do banco de dados ou algumas funções bem simples para realizar loops, imprimir constantes na tela e pouca coisa mais. Vamos manter nosso DBE bem simples, se depois alguém precisar de mais funcionalidades vamos permitir que se use o Smarty ou qualquer outro template engine pra renderizar nossas Views.

Até a próxima.

2006-12-04 13:22:49
tags: 

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 9)

Olá a todos. Mais uma vez estamos aqui (excepcionalmente escrevo numa segunda-feira, já que meu fim-de-semana foi totalmente dominado pelo PES6, também conhecido como Winning Eleven 10) pra falar de OOP, ou object-oriented programming. No último post, deixei bastante suspense no ar. O que é o design pattern MVC? Por que usar MVC neste projeto?

Como muitos que nos acompanham já sabem, muitas vezes este esquizofrênico autor acaba fazendo novas perguntas e dando respostas totalmente desvairadas às perguntas feitas anteriormente. Desvairadas no bom sentido, claro - para chegar à essência de qualquer coisa, primeiro temos que entender muito bem suas particularidades; portanto minha resposta à pergunta "O que é o design pattern MVC" vai ter duas etapas (consegui colocar 3 acentos graves em um só parágrafo. Uau.)

Etapa 1: O que é "Design Pattern"?

Design Pattern é o termo utilizado para definir uma prática bem estabelecida em arquitetura de software, uma solução clássica para um problema recorrente. Ou seja: meu amigo, esse problema que você está tendo muito provavelmente alguém muito mais inteligente e com mais disponibilidade de tempo já teve e já resolveu com uma classe, uma beleza que muito provavelmente você não conseguiria. É isso mesmo, o primeiro passo para se tornar um grande desenvolvedor (ou um chutador barato como eu) é aceitar a humildade em seu coração e perceber que as soluções mais bonitas já estão por aí. É só achar. E os design pattern clássicos são pura poesia em forma de código.

"Mas tudo bem, Danilo, eu sou humilde, mas ainda não entendi". Bom, aí, só mostrando na prática, não é mesmo? Então vamos lá, chegou a hora de não explicar o que é MVC.

Etapa 2: O que é "MVC"?

Model, View, Controller. É isso. Entendeu? Olha, se você ainda não entendeu, pode desistir. Não vai adiantar. Invente alguma outra coisa pra fazer, vá mexer no Photoshop, sei lá.

Brincadeirinha. O difícil dessa história de design pattern é compreender a beleza da solução. Só com o uso você pode entender. Eu poderia copiar e colar várias definições sobre o que é MVC, falar sobre toda a teoria, mas, como vocês já sabem, esta não é uma série convencional, e eu estou me propondo a mostrar essas coisas de um ponto de vista mais tosco. Algo como um PHP de rua, se é que vocês me entendem.

Então, pra mostrar ná prática o que é MVC, vou começar listando as coisas que mais me irritavam quando desenvolvia scripts PHP. Aí, se você não entender, realmente vai ser melhor ir fazer gifs animados lá no Photoshop, saca? :-)


- Lógica no meio do desenho da tela

Não existe nada mais desesperador do que lógica no meio do desenho da tela. Digo isso com conhecimento de causa, já que este é um dos piores problemas deste blog que vocês leêm nesse exato momento. É um inferno. Quero trocar o conteúdo de um link, mas ele está no meio de infindáveis ifs (perdoem o trocadilho) e depende de uma outra infinidade de variáveis que não sei mais de onde vieram e pra onde vão. Para criar o RSS feed do blog? Tive que começar do zero, o trabalho de editar o código que já existia nem valia a pena. Um outro exemplo clássico é a versão 2 do OsCommerce, o software open-source de comércio eletrônico. Tentem mudar qualquer coisa ali pra ver. Tem um milhão de condicionais e funções que rodam nas páginas de apresentação de conteúdo, entre um div e um p por exemplo. É coisa pra deixar qualquer um maluco. Um trabalho que poderia levar alguns dias me tomou 3 meses. Eu odeio isso com todas as minhas forças.

- Segurança $_GET e $_POST

Se você usa scripts php diversos para cada uma das páginas do seu site sabe muito bem que cada input do usuário, em cada página, precisa ser validado. Aí, digamos que você tenha 12 páginas php em seu site, e você copia e cola código em todas elas. Ok, agora, imaginemos ainda que 3 variáveis mudaram. Você tem que ir lá e copiar tudo de novo, doze vezes. Os mais espertinhos vão dizer "ah, mas é só fazer um include!", ao que eu respondo "mas, hey, amigo, cada página tem diferenças sutis em relação às outras, os dados comuns têm uma validação diferente de acordo com a situação do usuário e - deus que me livre - de acordo com seus níveis de permissão". Aí, cara, você cai duro, imaginando que aquele orçamento que você deu foi totalmente por água abaixo e que você vai ficar copiando e colando código para toda a eternidade, até que um dia não exista mais PHP no mundo e finalmente você possa descansar em paz.

OBSERVAÇÃO: Claro que dá pra fazer um site ou uma aplicação assim. O que nós estamos falando é de produtividade e capacidade de evolução com o tempo. Todo bom desenvolvedor que conheci é preguiçoso; afinal o computador foi criado pra que nós não tivessemos tanto trabalho, não é mesmo?


- Includes em múltiplos arquivos

Ah, includes. Os includes são uma bênção. Mas quando se tem 30 arquivos php para trabalhar, gerenciar includes se torna uma tarefa muito chata. Uma das soluções que a comunidade desenvolveu ao longo do tempo é o pattern "top.php", um arquivo que é incluído em todas as páginas do site, no topo, que por sua vez inclui outros 30 arquivos necessários ao funcionamento do site. Preciso dizer que tem desperdício de recursos aí? Aquela página que só precisa dos arquivos 1.php e 2.php acaba carregando o 3.php até o 30.php sem precisar. Bons desenvolvedores são higiênicos também; não gostam que tenha sujeira embaixo do tapete.

- SQL misturado com scripts php

Ah, essa é de doer. Já cansei de fazer código que tem SQL misturado, no meio dos scripts PHP. Sim eu era um "lousy coder", um desenvolvedor mixuruca, mas se você olhar tem muito código open source por aí assim. Meu Deus, como eu não via a gravidade desta heresia? Como eu não pude perceber que lugar de SQL não é no script que desenha minha tela? Que sql é coisa muito séria, que deve estar protegido, separado em classes que deixe tudo bem seguro pra que nenhum engraçadinho detone meus dados? Bem, acho que eu realmente não ligava. Mas quando a coisa começou a tirar a minha produtividade, e eu perdia horas procurando "cadê aquela query, acho que deve ser essa aqui" etc e tal a coisa ficou mais clara pra mim. Tinha que haver uma solução melhor pra isso.


Bom, o que posso dizer para vocês é que o pattern MVC resolve estes e muitos outros problemas, e uma vez tendo usado MVC você não vai querer mais voltar para o inferno. Mas tem uma questão: a coisa toda é mais complicada. Fato. Precisa pensar um pouco antes de sair escrevendo código. Precisa planejar. E esse planejamento é precisamente o que vamos começar a fazer no próximo artigo. Até lá.

p.s. o gnomo é o c...

2006-11-25 04:23:17
tags: 

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 8)

Olá todo mundo. Tudo pronto? Cintos de segurança afivelados? Mesinhas fechadas e travadas? Hoje começamos nossa longa jornada com um primeiro passo importante: definir algumas premissas do novo e nada revolucionário Digitalminds Blogging Engine 2.0, o primeiro software open-source para gerenciamento de blogs desenvolvido pela comunidade Digitalminds (o DBE 1.0, como vocês já sabem, é um script todo remendado, feito nas horas vagas, que não tinha código livre por que o autor tem vergonha de mostrar o ninho de rato que a coisa é).

Muito bem, então vamos às premissas:

do Lat. praemissa
cada uma das duas proposições, maior e menor, de um silogismo;
facto ou princípio que serve de base a um raciocínio ou a um estudo

Nossa primeira premissa é que nossas premissas serão as bases do nosso projeto, e que premissas só são alteradas para novas versões. Essa frase ficou um pouco redundante, eu sei, mas vocês vão ver que redundância é uma coisa muito importante quando se trabalha em grupo. Tudo precisa ser muito, muito, mas muito bem explicado para que não haja nenhum problema.

Que fique claro para todos, então, que depois da definição de nossas premissas para a primeira versão do projeto, só poderemos ter novas premissas para uma nova versão. Um dos maiores erros que podemos cometer é mudar de premissas durante o projeto. E, amigos, acreditem, vai ser muito tentador. Muitas vezes em projetos complexos dá muita vontade de mudar o que foi acordado antes, simplesmente por que todos aprendem ao longo do processo e percebem que algumas definições não fazem muito sentido. Mas como diz aquele deputado que não lembro mais o nome, "Versão boa é versão finalizada". É melhor ter um software na mão do que dois voando. Como estamos tentando aprender com o processo, vamos tentar manter a ordem e fechar a primeira versão conforme as premissas originais, ok?

Muito bem, senhores, então quais seriam as outras premissas para o projeto? Tenho algumas idéias que gostaria de sugerir:

- O DBE 2.0 vai rodar necessariamente em ambientes LAMP (Linux, Apache, MySql, PHP). Claro que não será difícil portar o sistema para outras configurações, mas não será nosso objetivo.

- O código será disponibilizado em um repositório Subversion(SVN), e todos poderão atualizá-lo sem restrições. A responsabilidade é sempre deixar a versão do trunk funcionando. Se você não entendeu nada dessa premissa, não se desespere. Vamos explicar diretinho o que é SVN, e dar todas as dicas para usar esse sistema de controle de versão fantástico.

- A versão 2.0 do DBE vai ter apenas o estritamente necessário, do ponto de vista das funcionalidades. Ponto final. Vamos tentar fazer para essa versão apenas o essencial. Se tivermos qualquer dúvida sobre uma funcionalidade, ela fica pra próxima.

- Como simplicidade é a palavra de ordem, não vamos construir nesse momento um sistema de autenticação. Vamos usar a autenticação Digest do Apache, ou mesmo a Basic, caso alguém não seja tão paranóico quanto eu. Trata-se de uma configuração bem simples que pode ser feita em um arquivo .htaccess no seu servidor. A vantagem da Digest é que ela usa criptografia para proteger a sua senha durante o envio. Pra quem não conhece os termos técnicos, autenticação do apache é aquela janelinha que abre em alguns sites pedindo pra você digitar a senha. Nada muito bonito, mas é bem seguro e fácil de implementar.

- A versão 2.0 do DBE vai ser escrita em PHP 5.1.4, usando orientação a objeto. Por quê esta versão? Bom, acho que esta é a primeira versão na qual a programação OOP realmente funciona 100%. Enfim, acho que não vai ser problema pra ninguém, praticamente todos os provedores bons já estão com esta versão, que por sinal tem outros updates importantes na área de segurança.

- Nosso DBE vai ser desenvovido usando modelo simplificado do design pattern mvc. por que usar o pattern mvc? O que é o pattern mvc?

Não perca o próximo capítulo! Só posso dizer que os gnomos estão chegando, amigos, e mais premissas também!


2006-11-18 03:25:25

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 7)

Olá pessoal, depois de mais um longo e tenebroso outono(?!) de muito, muito trabalho estamos de volta. Muito obrigado por todos os comentários e emails, mesmo estando totalmente atolado de trabalho na 32Bits™ eu tento ler todos e respondê-los o mais rapidamente possível. Pra quem tá chegando agora no blog, meu email é danilo[arroba]digitalminds.com.br e você pode ver todos os artigos dessa série clicando no título deste post, ok?

Bom, muitos escreveram perguntando sobre os gnomos. Quando eles vão aparecer nessa tão complexa trama? Qual é sua verdadeira identidade? O máximo que posso dizer é que eles tem contrato para 7 temporadas, e que talvez as respostas ainda demorem um pouco a vir... (funciona pro Lost, não? ;-)

Mas voltando ao que realmente interessa, OOP, ou object-oriented programming, hoje quero preparar o terreno para os próximos episódios. Agora que os conceitos principais já foram apresentados a vocês (se você ainda não sabe o que são classes, subclasses, interfaces, etc, talvez seja bom dar uma olhadinha nos artigos anteriores) gostaria de começar a parte Zen de nossa série. Como nossa marca registrada é gastar metade do artigo falando sobre coisas que são apenas marginalmente relacionadas ao assunto principal, vou tentar explicar o que é Zen em apenas uma palavra, sem nenhum compromisso de conseguir. Vamos lá:

Prática.

Talvez seja mais simples enumerar tudo o que o Zen não é. Zen não significa calma. A frase "Fulaninho é Zen, não se irrita com nada" basicamente não significa nada. Zen não é um conceito esotérico. Zen não é magia, tampouco feitiçaria.

Prática. Contar diariamente de um até dez. Koan. Tornar-se um com o arco. Concentração. Mente de principiante. Buda. E por aí vai.

E o que tudo isso tem a ver com OOP? Bem, caros leitores, a experiência de programação em oop só pode ser totalmente vivida na prática diária. Ler sobre oop é ótimo, mas é como olhar para o dedo que aponta para a Lua, e não olhar a Lua propriamente dita. Como verdadeiramente aprender estes conceitos? Vivendo-os. Como quebrar os Koans das classes, interfaces e patterns?

Recebi alguns emails pedindo que desse exemplos do uso da OOP em situações do dia-a-dia. Muito bem, então vamos começar uma nova etapa dessa série: Digitalminds 2.0.

Já faz tempo que quero refazer o Digitalminds Blogging Engine, que mesmo tendo esse nome bastante pomposo é um script muito furreca, todo remendado, escrito na correria entre trabalhos. Então, vamos nessa? Vamos refazer juntos o DBE, usando os conceitos que falamos, e, ao final do projeto, lançamos o DBE como um produto open source para livre download?

Acho que é uma idéia legal. Tudo bem que já existe o WordPress, etc e tal, mas... se a gente for por aí, TUDO já existe. A idéia é aprender e curtir o processo. Quem se habilita?

Até a próxima. Não percam o próximo artigo, vamos listar nossas premissas para o projeto e quero as opiniões de vocês. Abraço.

2006-09-17 05:34:55

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 6)

(Para ver todas as partes desta série clique aqui)

Olá, pessoal, já estamos aqui de volta para falar mais um pouquinho sobre OOP, PHP, e outras siglas igualmente ininteligíveis. Hoje quero falar sobre um tema que sempre gera muita confusão: interfaces. E, é claro, não podemos falar de interface sem olhar a etimologia dessa palavra.

O prefixo inter- vem da preposição latina inter, que significa "entre, no meio de". A palavra face, também de origem latina (fascia), significa "camada externa". Juntando as duas coisas, temos um termo genérico que significa praticamente qualquer coisa em tecnologia. Temos interfaces gráficas, interfaces com o usuário, interfaces RS232, interfaces usb, e por aí vai.

O conceito denominado de interface em OOP é bastante diferente disso tudo. No nosso mundo imaginário de carros, superpoderes, gnomos e outras criaturas fantásticas orientadas a objeto, interfaces são simplesmente definições padronizadas de acesso a funções que estão dentro das classes que as implementam. Falando assim parece bem complicado, mas não é não. Na verdade, na verdade, se a gente olhar com muito cuidado, nós de fato já usamos o conceito de interface aqui mesmo nos artigos anteriores.

Explico: quando nós criamos uma classe, estamos criando também uma interface. Lembra que nós construímos dois carros, um FiatUno e uma FerrariF1, e ambos podiam ->acelerar() ? Justamente! Ajoelhe-se diante do poder das interfaces!

Ao estender a classe Automovel para criar a classe FiatUno e a classe FerrariF1 nós estamos automaticamente implementando a interface usada na classe automóvel nas duas. Assim, temos absoluta certeza que todas as classes-filhas da classe Automovel vão poder ->acelerar(). Esse é exatamente o conceito de interface: a padronização do acesso aos dados e funções de uma classe ou objeto.

Mas o que é realmente interessante é que algum desses gênios malucos que inventaram os conceitos de OOP acordou um belo dia e teve uma idéia brilhante: "Perai, mas eu não preciso ter que criar classes-filhas toda hora pra usar uma interface!". Nasciam as palavras-chave interface e implements, que permitem a criação de interfaces que podem ser usadas entre classes que não tem nenhum parentesco entre si.

E eu estou aqui para provar tudo isso implementando Superpoderes em Automóveis! Você há de concordar que um Automovel não tem nada a ver com um SerHumano, já que eles não têm nenhum parentesco. Como ter certeza que essas classes e todos os seus filhos possam usar objetos da classe SuperPoder de forma padronizada? É fácil:

Primeiro, criamos a interface SuperHeroi:

 interface SuperHeroi {
    public function ativar(SuperPoder $superpoder);
} 

Bom, como você pode notar, a função ativar só vai funcionar se você mandar pra ela o SuperPoder desejado durante a chamada da função. Se mandar texto, número ou qualquer outra coisa vai ganhar um erro de presente.

Agora vamos alterar nossas classes Automovel e SerHumano para implementar a interface SuperHeroi:

Class SerHumano implements SuperHeroi { 	
    public $nome;
    public $vivo; 	
    public function __construct($nome) {
        $this->nome = $nome;
        $this->vivo = true;  	
    }
    public function taVivo() { 
        if($this->vivo == true) {             		
            print "Sim, eu estou vivo, e meu nome é $this->nome!"; 	
        } else {             	
            print "..."; 	
        }  	
    }
    public function ativar(SuperPoder $superpoder){
        $superpoder->ativar()
    }
} 

e agora a classe Automovel:

 abstract class Automovel implements SuperHeroi {
     public $aceleracao;
     public $velocidade_atual;
     public $cor;

     public function acelerar() {
        $this->velocidade_atual = $this->velocidade_atual + $this->aceleracao;
        print "Acelerando! Agora a velocidade é de " . $this->velocidade_atual . "Km/h!";
     }    
    public function ativar(SuperPoder $superpoder){
        $superpoder->ativar();
    }
 }

 

Agora, tanto os objetos SerHumano quanto objetos da classe Automovel (incluindo aqueles das classes FiatUno e FerrariF1, já que pela herança um FiatUno ou uma FerrariF1 sempre têm todas as propriedades e funções da classe Automovel) já podem ->ativar() um SuperPoder. Como a classe SuperPoder é abstrata e ninguém consegue ativar um SuperPoder abstrato, vou ativar a SuperForca:

$meucarro = new FerrariF1('vermelha'); 
$meucarro->ativar(new SuperForca);
// Meu deus, posso levantar um caminhão! 

E os gnomos, você deve estar se perguntando. Eles virão... Eles virão...

2006-09-03 17:34:59

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 5)

(Para ver todas as partes desta série clique aqui)

Olá pessoal. No último artigo da série a gente construiu carros e falou do conceito mais importante da programação orientada a objetos: herança. Só pra relembrar, o conceito de herança em Object-oriented programming (OOP) é a capacidade de criar uma classe com características próprias que serão transmitidas a todos os objetos criados a partir dela e a possibilidade de estender ou evoluir esta classe criando outras classes filhas, com novas capacidades além das originais.

Falando assim, parece bastante complicado. Mas é pura genética. Você é filho da classe "seu pai" e da classe "sua mãe", portanto tem características similares a eles. No entanto você também é uma classe à parte, pois tem diferentes comportamentos e características em relação a eles. Na verdade muitas linguagens não permitem que um objeto (você, no caso) seja filho de mais de uma classe, pra não complicar as coisas. Assim os objetos em PHP, por exemplo, são sempre filhos de uma única classe (seu pai OU sua mãe, no caso). Estranho? Espere até a gente falar dos gnomos. É aqui que entramos na parte maneira dessa semana. Superpoderes.

Digamos que você seja um ser humano normal, da classe SerHumano:

Class SerHumano {

    public $nome;

    public $vivo;

    public $superpoder;

    public function __construct($nome) {

        $this->nome = $nome;

        $this->vivo = true;

    }

    public function taVivo() {

        if($this->vivo == true){

            print "Sim, eu estou vivo, e meu nome é $this->nome!";

        } else {            

            print "...";

        }

    }

}

Bom, como você pode notar, os seres humanos da classe SerHumano não têm lá uma vida muito complicada não. Eles só têm um nome, a propriedade e uma funcão, taVivo(), que serve pra gente saber se o carinha ainda está vivo ou se já partiu desta pra melhor. Que vidão. Mas você percebeu que, assim como na vida real, todos os objetos da classe SerHumano tem o potencial de ter um superpoder. Sim, amigos, a variável $superpoder está lá para mostrar que todos os objetos podem da classe SerHumano podem ter um superpoder, desde que saibamos bem o conceito de Composição em programação orientada a objetos.

Vamos ver como um superpoder pode ser descrito:

abstract class SuperPoder {

    abstract function ativar();

}

Vocês lembram da classe Automóvel, abstrata demais pra poder existir como um objeto? A classe superpoder também é assim. Além disso, também definimos a função ativar como sendo abstrata, pra que necessariamente o superpoder defina como ela funciona. Como não dá pra ativar() um superpoder genérico, a gente diz que essa função é abstrata, forçando a definição nas classes que estendem a classe SuperPoder.

Então, na verdade, o que a gente acaba de fazer é criar uma classe para que todos os superpoderes tenham obrigatoriamente a mesma função, ativar, definindo um jeito único de usar todos os superpoderes do mundo. Aí, fica fácil depois um SerHumano ativar() qualquer superpoder, independentemente do que ele faz.

Esse truque também vai nos permitir fazer coisas muito interessantes com diferentes superpoderes, já que todos eles são filhos da mesma classe.

Continuando, vamos para a classe SuperForça:

class SuperForca extends SuperPoder {

    function ativar(){

        print "Meu deus! Posso levantar um caminhão!";

    }

}

Muito bem. Tudo pronto pra gente começar a criar objetos como se não houvesse amanhã. Vamos começar por você, um SerHumano como outro qualquer:

$voce = new SerHumano("Fulano");

$voce->taVivo(); // Sim, eu estou vivo, e meu nome é Fulano!

A função taVivo() confirma que você tá vivo. Muito bem, agora vamos dar a você, meu caro amigo Fulano, um SuperPoder!

$voce->superpoder = new SuperForca();

E pronto! agora você já pode usar seu super poder, já que a variavel $superpoder, que fica dentro do objeto $voce já contém o novo objeto SuperForca:

$voce->superpoder->ativar(); // Meu deus! Posso levantar um caminhão!

Parabéns! Você acaba de conhecer um dos conceitos fundamentais de orientação a objeto: a composição. Algumas vezes vai ser melhor compor diferentes classes para ter maior flexibilidade, como nesse caso, por exemplo.

Explico: se você quisesse agora criar um SuperCao, que não é um SerHumano, claro, seria muito simples. Crie a classe SuperCao já com uma variavel para guardar o SuperPoder e pronto! Se você tivesse definido o superpoder dentro da classe SerHumano o código já começaria a ficar redundante, já que você precisaria definir novamente a função dentro da classe SuperCao.

Tá muito confuso? Não estão gostando? Ou acharam muito bom? Mande seus comentários clicando no link [Comente] aí embaixo. Até a próxima pessoal!

2006-08-20 08:33:16

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 4)

(Para ver todas as partes desta série clique aqui)

Falar de cães, gnomos, seres imaginários e programação orientada a objetos não tão divertido sem falar de Carl Linnaeus , um estudante de medicina sueco nascido em 1707 que adorava coletar e estudar plantas. Naquele tempo o estudo da botânica era parte do currículo médico, já queas plantas forneciam a matéria-prima para a fabricação da maioria dos medicamentos.

Em 1735, ao completar seus estudos na Holanda, Carl publica a primeira edição de um dos livros mais importantes da história da humanidade: o Systema Naturae, sua tentativa de organizar e classificar toda a vida na Terra. Outros já haviam feito suas próprias classificações - Aristóteles, o sábio grego, teria feito a primeira tentativa conhecida, agrupando os animais "com sangue" e os "sem sangue". Como o nosso amigo sueco era bem prático, a primeira edição tinha apenas 11 páginas. Mas Linnaeus sabia que era o início de algo muito, muito importante.

Duzentos e setenta e um anos depois muita coisa mudou mas a obra de Carl Linnaeus continua viva, atualizada ano após ano com novas descobertas e mudanças paradigmáticas. Nem é preciso dizer que o trabalho de Charles Darwin também influenciou e muito a classificação da vida. Mas isso não é tão importante agora, na verdade. O importante para nossa conversa é o conceito de classificação em si; Trata-se de uma idéia fundamental para nós, seres humanos; tudo o que vemos e criamos é instintivamente classificado e organizado em grupos similares, de acordo com características que podemos perceber ou mesmo de acordo com padrões sócio-culturais. Por exemplo: se a gente vê uma coisa com caule, galhos e folhas a gente imagina que seja uma árvore, se a gente vê uma coisa com quatro patas que late a gente imagina que seja um cachorro, e se a gente vê uma criaturinha pequena, vestida de verde com uma longa barba branca a gente imagina que seja um gnomo. Mesmo que os conceitos "árvore", "cachorro" e "gnomo" não existam pra nós (digamos que você seja um esquimó vivendo numa ilha totalmente isolada no polo súl que só tem pinguins) é possível perceber, só de olhar para duas "coisas" dessas, que elas são similares. Esse é o exatamente o conceito de classe original - um grupo de coisas com características comuns.

Pra tornar as coisas um pouco mais confusas, a biologia se apropriou deste termo e na classificação biológica atual ele tem um sentido mais específico, um determinado ponto da hierarquia de classificação e se junta a outros termos como espécie, gênero, reino, entre outros. Exemplo: um cachorro é da classe mammalia, ordem Carnivora, família Canidae, espécie Canis lupus. Mas então vamos esquecer tudo isso, e lembrar somente do conceito original da palavra classe - coisas com a mesma classe têm as mesmas características. Tudo bem? Então agora a gente pode generalizar: eu agora te digo que dois objetos que sejam da mesma classe têm as mesmas características e as mesmas funções. Tipo, uma Ferrari F1 tem a mesma classe de um Fiat Uno, sacou? Os dois são automóveis, servem pra se locomover, têm quatro rodas, etc e tal. Agora, claro que uma Ferrari F1 é bem diferente de um Fiat Uno (quem já teve os dois sabe do que eu estou falando :-D Então também podemos dizer que cada um deles faz parte de uma classe mais específica, que estende o conceito da classe Automóvel, que vamos chamar de classe-mãe.

Repare que objetos que sejam somente da classe Automóvel não existem na realidade - é impossível entrar numa loja e comprar um automóvel abstrato, você sempre vai ter que comprar um automóvel de verdade, certo? Então podemos dizer que essa classe é abstrata. Com isso na cabeça, olha o seguinte "código":

abstract class Automovel {    

    public $aceleracao;    

    public $velocidade_atual;    

    public $cor;        

    public function acelerar() {        

        $this->velocidade_atual = $this->velocidade_atual + $this->aceleracao;        

        print "Acelerando! Agora a velocidade é de " . $this->velocidade_atual . "Km/h!";    

    }

}

class FerrariF1 extends Automovel {    

    public function __construct($cor){        

    $this->cor = $cor;         $this->aceleracao = 50;    

    }

}

class FiatUno extends Automovel {    

    public function __construct($cor) {

        $this->cor = $cor;        

        $this->aceleracao = "1";    

        }

}

Ficou difícil? Bom, não é tão difícil não. É o seguinte: A classe Automovel define as características similares de todos os automóveis. Todos eles têm cor, uma aceleração, e uma função acelerar para aumentar a velocidade atual. Simples. As classes FerrariF1 e FiatUno estendem esse comportamento sem perder as características originais da classe Automóvel: mesmo sem definir a funcao "Acelerar" dentro dessas classes as FerrarisF1 e FiatUnos vão poder acelerar, sem problemas.

A funcão __construct (esse nome pode variar de acordo com a linguagem de programação que você estiver usando, no caso estou mostrando o exemplo na linguagem PHP, versão 5) é a fábrica de automóveis: ao ser chamada ela constrói uma FerrariF1 ou um FiatUno de acordo com as especificações. Se eu pedir

    $meucarro = new FerrariF1("vermelha");

A fábrica vai construir pra mim uma FerrariF1 com a cor vemelha. Um luxo. Vou comprar um carro pra você:

     $seucarro = new FiatUno("branco");

E o pessoal de Betim já deve estar correndo pra pintar o Uno de branco uma hora dessas.

A aceleração é diferente: No caso das FerrariF1, elas já nascem com uma aceleração de 50. O Uno não anda tão rápido assim e nasce com uma aceleração de 1. Então tá na hora de apostar corrida;

    $meucarro->acelerar(); // Acelerando! Agora a velocidade é de 50Km/h!

    $seucarro->acelerar(); // Acelerando! Agora a velocidade é de 1Km/h!

Cara, acho que você devia comprar um carrinho melhor, viu? E os gnomos, você deve estar se perguntando. Os gnomos são como automóveis, meu amigo... só que de uma classe diferente.

2006-08-14 04:24:47

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 3)

(Para ver todas as partes desta série clique aqui)

Bom, quem ainda não sabe a diferença entre Programação Procedural e Orientação a Objeto não se desespere. Vou tentar mostrar um pouco dessa diferença da forma mais simples possível, começando bem do início. Mas não esperem nada muito técnico ou sofisticado - vou falar um pouco da minha experiência e dar exemplos que me ajudaram a entender melhor esses conceitos, sem nunca ter a pretensão de estar estritamente certo. Aliás, peço que todos os leitores mandem referências e ajudem a esclarecer as dúvidas que porventura aparecam, ok?

Programação procedural, como o próprio nome diz, é o paradigma de programação baseado em procedures, conhecidas no Brasil como rotinas ou subrotinas. De acordo com a wikipedia, programas que usam funções ou métodos, cujo conceito é um pouco diferente das subrotinas, também são incluídos nesse grupo.

Então, o que são subrotinas? Lá na minha adolescência, cansei de escrever programas como esse:

10 print "Qual e a sua idade?"
20 input i
30 if i > 25 then gosub 100 else gosub 150
40 print "Ate mais. Fui."
40 end
100 rem *** Subrotina 1 ***
110 print "Voce e muito novo! Nao conhece programacao basic!"
120 return
150 rem *** Subrotina 2 ***
160 print "Voce deve ter feito curso de basic..."
170 return


O programa acima é muito simples. Ele pergunta a idade do usuário e imprime na tela uma mensagem de acordo com a sua resposta. Essa é a grande qualidade das linguagens de programação procedurais: elas são extremamente simples de se usar, e são orientadas à tarefa que se quer realizar.

"Primeiro pegue a idade do cara, depois teste se ele tem mais que 25 anos, e então imprima um dos textos de acordo".

Se eu pudesse fazer uma descrição meio simplória, diria que fazer programação procedural é como dar ordens para seu computador. Faça isso, depois isso, depois aquilo. É como treinar um cachorro, digamos. Agora senta! Isso, bom garoto! Mas, à medida que você vai ensinando coisas mais complexas pro seu cachorro, você sabe como as coisas começam a ficar complicadas. Experimente ensinar o seu cachorro a


10 Latir
20 Pegar o jornal na porta
30 Trazer o jornal
40 Latir
50 Sentar
60 Deitar
70 Fingir de morto


e depois tente ensinar o pobre quadrúpede a primeiro verificar se o jornal está realmente na porta (pobre cachorro, vai ficar muito angustiado se o jornaleiro não deixar o jornal algum dia) e caso não esteja lá, que ele saia correndo pra pegar o moleque que não trouxe o jornal.

É muito provável que o seu amigo canino fique completamente perdido. Perdão por essa analogia meio insana, mas assim também funciona com os programas desenvolvidos em programação procedural - eles são bastante difíceis de manter e atualizar. Nada que não se resolva colocando vários treinadores, digo, programadores, mas você pode imaginar que o custo de treinar esse cachorro vai crescer exponencialmente ao longo do tempo.

E qual a diferença entre programação procedural e OOP afinal? Bom, por mais que sempre exista algum grau de programação procedural em qualquer linguagem, nas linguagens orientadas a objeto você passa menos tempo falando com seu computador e mais tempo falando com gnomos e seres imaginários. Ou, pra continuar usando a metáfora animal, com cachorros de várias raças, gatos, papagaios e até um sapo falante. Explico melhor no próximo post.
2006-08-04 04:55:01

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 2)

(Para ver todas as partes desta série clique aqui)

Eram tempos interessantes, aqueles. De um dia pro outro, os Cursos de Programação Basic começaram a pipocar na cidade toda. A coisa virou currículo obrigatório para os adolescentes de classe média, quase tão importante como um curso de inglês no IBEU ou na Cultura Inglesa. A informática era o futuro, e naquela época programação era sinônimo de informática.

Empolgadíssimo, me matriculei em meu primeiro curso de programação. Todas as quartas e sextas era aquela expectativa: simplesmente não aguentava esperar pra entrar naquela sala cheia de CP-500s com monitor de vídeo verde de 80 colunas e placa cp-m. Era simplesmente o máximo. O M-Basic era o que existia de mais maneiro na época, e os computadores com chip z-80 de 4MHZ (na versão turbo!) e 16Kb de memória o que havia de mais avançado e profissional em microinformática.

Mas o que tudo isso tem a ver com meu árduo caminho no aprendizado da programação orientada a objeto? Bom, os iniciados sabem que o M-Basic, mesmo sendo uma linguagem de programação simples e divertida para se aprender, é uma linguagem procedural. Naquela época, a orientação a objeto ainda estava restrita ao meio acadêmico e aos desenvolvedores realmente Casca Grossa™.

E como eu pude ver anos mais tarde, tentar compreender conceitos de orientação a objeto depois de ter passado toda a vida programando de forma procedural pode ser muito, muito difícil.
(Continua)
2006-07-29 07:17:46

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 1)

(Para ver todas as partes desta série clique aqui)

Um grande abraço a todos que (ainda) acompanham o digitalminds! Já faz algum tempo, não? Estive ocupado com outras coisas não menos importantes e me faltou a combinação certa de assuntos e disposição para escrever por aqui. Finalmente acho que o momento de escrever chegou.

Nos últimos meses, além de me dedicar ao meu trabalho na 32Bits™ e ao Wasabi, me interessei profundamente por dois assuntos aparentemente desconexos: a prática do zazen, ou meditação zen sentada, e programação orientada a objeto, também conhecida como OOP (do inglês Object Oriented Programming). O que poderia ser comum a uma tradição milenar como o budismo zen e a um paradigma de programação criado no século XX? A explicação vai ser um pouco longa, me perdoem, mas garanto que a história é divertida!

Vamos começar voltando ao ano de 1985, quando fiz meu primeiro curso de programação. Naquela época, alguns de vocês hão de lembrar, a microinformática ainda estava dando seus primeiros passos, e os microcomputadores apenas começavam a chegar nas casas das famílias de classe média. Um belo dia, depois de uma viagem de uma tia aos Estados Unidos, me vi diante do meu primeiro computador: um legítimo Commodore Vic-20, novínho em folha.

Pra ser muito franco, dizer que era o "meu" computador é um certo exagero, já que a razão principal da compra do aparelho era a paixão do meu pai por xadrez. De fato, como o computador tinha apenas 8k de memória, não dispunha de disco rígido (disco rígido?) e nem mesmo tinha um adaptador para gravador cassete, sua única utilidade prática era rodar o programa que estava no cartucho "Sargon II Chess".

Essa estranha combinação de fatores trouxe uma consequência muito interessante: quando eu retirava o tal cartucho, o prompt característico do CBM Basic V2 aparecia, mostrando a enorme memória livre de 3583 bytes e fazendo a minha imaginação criar todo tipo de programas que se possa imaginar. Aquele cursor, piscando ali na tela, era quase uma provocação.

Direto do manual, em inglês, fiz meu primeiro programa:

10 print "*"
20 goto 10

Uau. Um novo universo estava se abrindo diante dos meus olhos. Segundos depois, o desespero: "Mas como é que eu paro isso", pensei. A tela cheia de asteriscos, cadê o cursor? Estava claro que precisava entender melhor aquilo tudo.

(Continua)