Revista Do Linux
 
 

PEAR, a biblioteca de Classes do PHP4

A versão 4 do PHP dá aos desenvolvedores que querem trabalhar com classes e objetos a biblioteca Pear. Conheça-a e aprenda a utlizar seus componentes

Introdução

Desde a versão 3, o PHP possui recursos de orientação a objetos, que são utilizados extensivamente por bibliotecas populares como a PHPLib e o FastTemplates. Por outro lado, a distribuição padrão do PHP continuava fornecendo apenas os módulos procedurais escritos em linguagem C, e o programador PHP mediano se limitava, quando tanto, a utilizar as classes prontas fornecidas por estas bibliotecas enquanto que o seu próprio código não tirava proveito dos recursos OO.

A versão 4 do PHP não é mais nenhuma novidade, entretanto ela fornece uma infra-estrutura para o desenvolvedor que deseja trabalhar com classes e objetos, além de uma biblioteca de classes contendo vários componentes úteis, a biblioteca PEAR.

A maior parte da literatura disponível na Internet continua focalizando apenas os recursos procedurais do PHP, e o resultado é que os desenvolvedores subutilizam a linguagem por desconhecer os recursos OO e a PEAR.

Orientação a Objetos e o PHP

Para os desenvolvedores habituados a Object Pascal, C++ ou Java, o PHP pode parecer uma linguagem OO de “segunda categoria” porque não possui alguns recursos presentes nestas linguagens, tais como:

• Métodos destrutores
• Herança múltipla
• Restrições de visibilidade (public, protected, private)
• Classes abstratas e/ou interfaces
• Casts
• Exceções

Mas isto não é necessariamente ruim. Os Casts, por exemplo, não são necessários em uma linguagem fracamente tipada como o PHP, assim como as classes abstratas e interfaces, pois não há necessidade de tipos base para a construção de algoritmos genéricos. A herança múltipla é um recurso que é cada vez mais contestado na comunidade OO, tanto que Java e Python não suportam.

Por outro lado, o PHP implementa alguns recursos avançados de OO, que sem dúvida a qualificam como uma linguagem OO de primeira categoria:

• Referências
• Serialização
• RTT e Introspecção

Recomendo que o leitor investigue a documentação do PHP sobre estes tópicos, mas detalhá-los aqui sairia do foco deste artigo.

A Biblioteca PEAR

Segundo a home-page do PEAR, ele é “um framework e um sistema de distribuição para componentes PHP reutilizáveis”. O PEAR foi inspirado no CPAN, The Compreensive Perl Archive Network, a gigantesca e bem-sucedida biblioteca de código Perl.

Um componente, para ser incluído no PEAR, deve atender a uma série de requisitos:

• Primeiro, ele precisa ser aprovado, baseado na sua utilidade, qualidade e consistência, pelos mantenedores do PEAR e pela comunidade de um modo geral.
• Deve seguir as convenções de codificação do PEAR, de modo que todo o código seja compreendido e manutenível por qualquer integrante da comunidade.
• Utiliza um mecanismo padronizado de tratamento de erros.
• Possui documentação no formato PHPDoc.
• Traz exemplos de utilização e casos de testes para o desenvolvimento.

A maioria dos componentes do PEAR é escrita em PHP, mas alguns deles podem ser escritos em C, sendo por isso chamados de PECL. Os componentes do PEAR são divididos em “core components” (componentes essenciais), que são incluídos nas distribuições padrões do PHP, e “packages” (pacotes), que são componentes opcionais do PEAR que podem ser baixados e instalados automaticamente quando o desenvolvedor desejar. Esta separação visa (1) isolar a infra-estrutura necessária para o funcionamento do próprio PEAR e (2) não tornar a distribuição do PHP grande demais para download.

Os “core componentes” do PEAR são:

• Base e tratamento de erros.
• Console, com suporte a scritps PHP que rodam interativamente ou via cron, desatrelados de um web server, fornecendo o GNU Getopt para tratamento das opções da linha de comando.
• DB, uma API independente de banco de dados.
• HTTP, utilitários para cabeçalhos e outros recursos do HTTP.
• Mail, classes para a construção e processamento de mensagens MIME.
• Networking, suporte a sockets TCP e UDP.
• System, interface para o gerenciamento de arquivos pelo sistema operacional.

E entre os pacotes disponíveis temos:

• Autenticação
• Log
• Templates
• PHPUnit (testes automatizados estilo XP)
• PHPDoc (geração de documentação)
• Imagick (tratamento de imagens)
• XML
• Cliente CORBA

Criando Componentes PEAR

Um componente PEAR deve obedecer a quatro regras básicas:

1. Estender a classe PEAR.
2. Todas as suas instâncias devem ser utilizadas por meio de referências (&new).
3. Deve implementar um método _NomeDaClasse para liberar quaisquer recursos criados no construtor, como arquivos, sockets e conexões a bancos de dados.
4. Deve retornar instâncias de PEAR_Error ou classes derivadas sempre que algum método detectar uma situação de erro.

Os principais objetivos da classe PEAR são fornecer uma emulação de métodos destrutores (que não existem no PHP) e um mecanismo padrão de tratamento de erros.

O construtor da classe PEAR salva uma referência para a nova instância em um array global e registra uma função de shutdown para o PHP, que irá varrer este array ao fim do script, chamando para cada objeto o método _NomeDaClasse. Desta forma, evitamos “resource leaks” em scripts PHP.

Um exemplo deve deixar as coisas mais claras.

No exemplo 1, é fundamental que seja utilizado “&new” e não “new” para instanciar a classe, caso contrário, teremos uma instância da classe armazenada pelo PEAR e outra em uso pelo script. Se isto acontecer, o PEAR não poderá garantir que todos os arquivos ou conexões foram encerrado.

Agora vamos ver no exemplo 2 como deve ser o tratamento de erros em componentes PEAR.

O método raiseError cria uma instância de PEAR_Error, mas você também poderia criar a sua própria classe personalizada derivada de PEAR_Error e instanciá-la com &new.

Vários dos pacotes do PEAR criam as suas próprias classes, como por exemplo, a classe DB_Error (pacote DB) que contém o código e mensagem de erro do banco de dados.

O Pacote DB do PEAR

No exemplo 3, mais interessante dos componentes do PEAR em ação, vamos ver como um script que acessa uma tabela em um banco de dados MySQL poderia ser reescrito com o pacote DB. Primeiro, eis o programa utilizando o módulo mysql do PHP.

Caso esta aplicação tenha que ser portada para o PostgreSQL, Firebird ou Oracle, deveremos trocar cada função mysql_* pela equivalente na API do outro banco, com possíveis mudanças na lógica do script. Além disso, cada API de banco tem a sua própria maneira de retornar erros, tópico que foi completamente ignorado no exemplo acima.

Vamos agora ver a mesma aplicação utilizando o pacote PEAR DB, no exemplo 4.

Mudar a aplicação para trabalhar com um servidor PostgreSQL envolve a mudança de uma única linha:

$con = DB::connect (“pgsql:/usuario:senha@localhost”);

Ou para utilizar o Oracle:
$con = DB::connect (“oci8://usuario:senha@orcl”);

Onde “orcl” é o nome da conexão configurada no NetAssistant do cliente Oracle. O pacote DB é bem simples, fornecendo apenas duas classes: DB (o objeto $con no exemplo acima) e DB_Result (o objeto $rs). Ele também define duas classes adicionais, DB_Error e DB_Warning.

O exemplo não realiza qualquer tratamento de erros, mas, caso se queira, poderia ser feito segundo o padrão do PEAR, no exemplo 5.

O acesso a bancos de dados via PEAR DB não é mais lento, pois as classes específicas para cada banco de dados (instanciadas pelo método de fábrica DB::connect) utilizam os módulos procedurais que chamam as APIs nativas de cada banco. Existe apenas o overhead extra de uma chamada de método, que é quase nada. É um preço bem pequeno a ser pago para obter compatibilidade com qualquer banco suportado pelo PHP.

exemplo 1

<?php
require_once (“PEAR.php”);

class ContaCorrente extends PEAR
{
    var $log;
    var $saldo;

    // construtor
    function ContaCorrente () {
        $this->PEAR ();
        $log = fopen (“/tmp/logcaixa”, “a”);
         // ... outras inicializações
    }

    function saque ($valor) {
         // ... utiliza $log para registrar todas as operações 
        // ...  realizadas pelo caixa com fins de auditoria
    }

    // destrutor
    function _ContaCorrente () {
        if (is_resource ($log))
            fclose ($log);
         // ... outras tarefas para “limpar a casa”
    }
}

$caixa = &new ContaCorrente ();
$caixa->saque (100);

?>
exemplo 2

<?php

require_once (“PEAR.php”);

class ContaCorrente extends PEAR
{
    // ...

    function saque ($valor) {
        if ($this->saldo < $valor)
            >return $this->raiseError (“Saldo insuficiente”);
        // ... realiza o saque 
    }

    // ...
}

// ...

$err = $caixa->saque (100);
if (PEAR::isError ($err)) {
    echo (“Não pude realizar o saque:<BR>”);
    echo ($err->getMessage ());
}
else {
   // ...
}
?>

exemplo 3

<?php
    // conecta ao banco
    $con = mysql_connect (“localhost”, “usuario”, “senha”);
    mysql_select_db (“banco”);
    // executa um comando SQL
    $sql = “SELECT nome, e_mail FROM agenda ORDER BY nome”;
    $rs = mysql_query ($sql, $con);
    // formata o resultado como uma tabela HTML
    echo (“<TABLE border>”);
    echo (“<TR><TD>Nome</TD><TD>E-mail</TD></TD>”);
    while ($row = mysql_fetch_row ($rs)) {
        echo (“<TR><TD>{$row[0]}</TD>”);
        echo («<TD>{$row[1]}</TD></TR>»);
    }
    echo (“</TABLE>”);
    // fecha a conexão, se eu esquecer terei um resource leak
    mysql_free_result ($rs);
    mysql_close ($con);
?>

exemplo 4

<?php
    include “DB.php”;
    // conecta com o banco
    $con = DB::connect (“mysql://usuario:senha@localhost/banco”);
    // executa um comando SQL
    $sql = “SELECT nome, e_mail FROM agenda ORDER BY nome”;
    $rs = $con->query ($sql);
    // formata o resultado como uma tabela HTML
    echo (“<TABLE border>”);
    echo (“<TR><TD>Nome</TD><TD>E-mail</TD></TD>”);
    while ($row = $rs->fetchRow ()) {
        echo (“<TR><TD>{$row[0]}</TD>”);
        echo («<TD>{$row[1]}</TD></TR>»);
    }
    echo (“</TABLE>”);
    // fecha a conexão, mas o PEAR cuida disso se eu esquecer
    $rs->free ();
    $con->disconnect ();
?>

exemplo 5

<?php
    //...
    $con = DB::connect ($dsn);
    if (DB::isError ($con)) {
        // ...
    }
    $rs = $con->query ($sql);
    if (DB::isError ($rs)) {
        // ...
    }
    while ($row = $rs->fetchRow ()) {
        if (DB::isError ($row)) {
            // ...
        }
    }
    //...
?>

Para saber mais:
PEAR: pear.php.net
PEAR DB: pear.php.net/manual/en/core.db.php
CPAN: cpan.perl.com
PHPDoc: pear.php.net/manual/en/packages.phpdoc.php
FastTemplates: www.thewebmasters.net
PHPLib: phplib.sourceforge.net
Página pessoal do autor, que contém mais exemplos e tutoriais sobre PHP: www.lozano.eti.br


Fernando Lozano - fernando@lozano.eti.br

A Revista do Linux é editada pela Conectiva S/A
Todos os Direitos Reservados.

Política de Privacidade
Anuncie na Revista do Linux