introdução à linguagem php · pdf filefundamentos de poo enquanto o...

27
Introdução à Linguagem PHP Manipulando erros em PHP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title></title> </head> <body> <?php function myErrorHandler($errno, $errstr, $errfile, $errline) { switch ($errno) { case E_NOTICE: case E_USER_NOTICE: $errors = "Notice"; break; case E_WARNING: case E_USER_WARNING: $errors = "Atenção"; break; case E_ERROR: case E_USER_ERROR: $errors = "Fatal Error"; break; default: $errors = "Desconhecido"; break; } if (ini_get("display_errors")) printf ("<br />\n<b>%s</b>: %s em <b>%s</b> na linha <b>%d</b><br /><br />\n", $errors, $errstr, $errfile, $errline); if (ini_get('log_errors')) error_log(sprintf("PHP %s: %s in %s on line %d", $errors, $errstr, $errfile, $errline)); return true; } // Configurar o manipulador de erros set_error_handler("myErrorHandler"); // Forçar um erro de divisão por ZERO echo 4/0; ?> </body> </html> Programação Orientada a Objeto em PHP (Extraído do Livro “Zend PHP 5 Certification Study Guide”) A Orientação a Objetos no PHP em sua 5ª versão foi totalmente reescrita do zero. Neste capítulo, presume‐se que o aluno esteja familiarizado com os conceitos de OO para que possa usufruir de seu poder aplicado ao PHP.

Upload: vankiet

Post on 16-Mar-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

Introdução à Linguagem PHP

Manipulando erros em PHP

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title></title> </head> <body> <?php function myErrorHandler($errno, $errstr, $errfile, $errline) { switch ($errno) { case E_NOTICE: case E_USER_NOTICE: $errors = "Notice"; break; case E_WARNING: case E_USER_WARNING: $errors = "Atenção"; break; case E_ERROR: case E_USER_ERROR: $errors = "Fatal Error"; break; default: $errors = "Desconhecido"; break; } if (ini_get("display_errors")) printf ("<br />\n<b>%s</b>: %s em <b>%s</b> na linha <b>%d</b><br /><br />\n", $errors, $errstr, $errfile, $errline); if (ini_get('log_errors')) error_log(sprintf("PHP %s: %s in %s on line %d", $errors, $errstr, $errfile, $errline)); return true; } // Configurar o manipulador de erros set_error_handler("myErrorHandler"); // Forçar um erro de divisão por ZERO echo 4/0; ?> </body> </html>

Programação Orientada a Objeto em PHP (Extraído do Livro “Zend PHP 5 Certification Study Guide”)

A Orientação a Objetos no PHP em sua 5ª versão foi totalmente reescrita do zero. Neste capítulo, presume‐se que o aluno esteja familiarizado com os conceitos de OO para que possa usufruir de seu poder aplicado ao PHP.

Page 2: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

Fundamentos de POO

Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é uma boa idéia dar uma breve olhada em alguns de seus fundamentos. A POO remonta o conceito de agrupar código e dados juntos em unidades lógicas chamadas classes. Este processo é usualmente conhecido como encapsulamento, ou ocultação de informações, desde que seu objetivo é dividir uma aplicação em entidades separadas cujos componentes internos podem ser alterados sem alterar suas interfaces. Então classes são essencialmente uma representação de um conjunto de funções (conhecidas por métodos e variáveis (conhecidas por propriedades ou atributos) projetadas para trabalharem juntas e fornecer uma interface específica para o mundo externo. É importante entender que classes são apenas plantas que não podem ser usadas diretamente – elas têm que ser instanciadas em objetos que podem interagir com o resto da aplicação.

Declarando uma classe

A declaração básica de uma classe é muito simples: Class myClass { //Conteúdo aqui } Como você pode perceber, esse código avisa ao interpretador PHP que você está declarando uma classe chamada myClass cujo conteúdo será normalmente uma combinação de constantes, variáveis e funções (métodos).

Instanciando um Objeto

Uma vez que tenha declarado uma classe, você precisa instanciá‐la para obter as vantagens que ela oferece. Isso é feito usando o construtor new: $myInstance = new myClass(); No PHP 5, os objetos são tratados de maneira diferente dos outros tipos de variáveis. Um objeto é sempre passado por referência ao invés de por valor. Por exemplo: $myClassInstance = new myClass(); $copyInstance = $myClassInstance(); Neste caso, ambas as variáveis myClassInstance e copyInstance apontarão para o mesmo objeto. Isso é um comportamento padrão dos objetos na maioria das linguagens, mas não era o caso no PHP 4.

Herança de classe

Um dos fundamentos chave da POO é a herança. Ela permite que uma classe estenda outra, essencialmente para adicionar novos métodos e propriedades, bem como redefinindo‐os caso já existentes. Por exemplo: class a { function test() {

echo "a::test called"; } function func() {

Page 3: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

echo "a::func called"; } } class b extends a { function test() {

echo "b::test called"; } } class c extends b { function test() {

parent::test(); } } class d extends c { function test() {

b::test(); } } $a = new a(); $b = new b(); $c = new c(); $d = new d(); $a->test(); // Outputs "a::test called" $b->test(); // Outputs "b::test called" $b->func(); // Outputs "a::func called" $c->test(); // Outputs "b::test called" $d->test(); // Outputs "b::test called" Nesse script, começamos declarando uma classe chamada “a”. Então declaramos a classe “b” que estende “a”. Como pode ver, a classe “b” também tem o método test() que redefine aquele declarado em “a”. Perceba que ainda podemos, no entanto, acessar os outros métodos de “a”. Por exemplo, se chamarmos $b->func(), estamos efetivamente chamando o método func() de “a”.

Métodos e propriedades de classe

Como mencionado anteriormente, classes podem conter métodos e variáveis (propriedades). Métodos são declarados do mesmo jeito das funções tradicionais: class myClass { function myFunction() { echo "You called myClass::myFunction"; } } Do lado de fora do escopo de uma classe, seus métodos são chamados usando o operador ‐>: $obj = new myClass(); $obj->myFunction(); Realemente, a variável $obj só é válida dentro do escopo de nosso pequeno trecho de código acima – que nos deixa com um dilema: como referenciar um método de classe de dentro da própria classe? Aqui vai um exemplo: class myClass {

function myFunction() {

Page 4: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

echo "You called myClass::myFunction"; } function callMyFunction() {

// ??? }

} Claramente, callMyFunction() precisa de uma maneira de chamar myFunction() de dentro do escopo do objeto. Para que isso seja possível, o PHP dispõe de uma variável especial chamada $this. Ele sempre se refere ao próprio objeto. Exemplo: class myClass {

function myFunction($data) { echo "The value is $data";

} function callMyFunction($data) {

// Call myFunction() $this->myFunction($data);

} } $obj = new myClass(); $obj->callMyFunction(123); Este trecho de código mostrará “The value is 123”.

Construtores

O PHP introduziu o conceito de construtor unificado e, juntamente com ele, um novo destruidor de objetos. O construtor e o destruidor são métodos especiais de classe que são chamados, como seus nomes sugerem, na criação e destruição dos objetos, ou para executar procedimentos de inicialização. Nas versões anteriores do PHP, construtores tinham o mesmo nome da classe. Agora, utiliza‐se o método __construct(). Isso é útil, pois caso queira renomear a classe, não será preciso renomear os construtores. Exercício: verifique se é possível existir mais de um método construtor na mesma classe. class foo {

function __construct() {

echo __METHOD__; } function foo() {

// PHP 4 style constructor }

} new foo();

Destruidores

Além do método __construct(), temos também o método __destruct(). Ele trabalha como uma imagem de espelho do __construct(). Ele é chamado logo antes de um objeto ser destruído e é útil para executar operações de limpeza, como desconectar de um recurso remoto ou apagar arquivos temporários: class foo {

function __construct()

Page 5: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

{ echo __METHOD__ . PHP_EOL; } function __destruct() { echo __METHOD__; }

} new foo(); Esse código mostrará: foo::__construct foo::__destruct A destruição ocorre quando qualquer referência a um objeto desaparece, como no caso abaixo: $a = new foo(); $b = $a; unset($a); Mesmo que um objeto ainda possua uma ou mais referências ativas, o método __destruct() é chamado no final da execução do script, então você terá a garantia de que em algum momento seu destruidor será executado. Entretanto, não há uma maneira de determinar a ordem de destruição de dois ou mais objetos. Isso pode causar algum problema quando um objeto depende de outro para executar uma ou mais funções.

Visibilidade

O PHP 5 adicionou a noção de visibilidade de métodos e propriedades de objetos , que permite que você determine o escopo a partir do qual cada componente de sua classe possa ser acessado.

• public O recurso pode ser acessado a partir de qualquer escopo.

• protected O recurso só pode ser acessado de dentro da classe onde está definido ou a partir de seus descendentes.

• private O recurso só pode ser acessado de dentro da classe onde está definido.

• final O recurso pode ser acessado a partir de qualquer escopo, mas não pode ser redefinido ou sobrecarregado.

OBS: o nível de visibilidade final somente se aplica a métodos e classes. Classes que são declaradas como final não podem ser estendidas. Normalmente, você irá querer tornar todos os métodos e propriedades de sua API públicas, desde que queira torná‐los acessíveis de fora de seus objetos, enquanto você desejará manter as operações internas protegidas ou privadas. Construtores e destruidores são normalmente declarados como públicos, entretanto, às vezes você pode desejar tornar os construtores privados quando, por exemplo, quer usar alguns padrões de projeto como o Singleton ou Factory: class foo {

public $foo = ’bar’; protected $baz = ’bat’; private $qux = ’bingo’; function __construct() {

var_dump(get_object_vars($this)); }

}

Page 6: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

class bar extends foo { function __construct() {

var_dump(get_object_vars($this)); }

} class baz {

function __construct() { $foo = new foo(); var_dump(get_object_vars($foo));

} } new foo(); new bar(); new baz(); O exemplo acima cria três classes: foo, bar que estende foo e tem acesso a todos os métodos e propriedades públicos e privados de foo e, finalmente, baz que cria uma nova instância de foo e pode somente acessar suas propriedades públicas. Execute o programa e observe a saída.

Declarando e Acessando Propriedades

Propriedades são declaradas em PHP orientado a objetos usando um dos modificadores de acesso mencionados anteriormente, seguido de seus respectivos nomes: class foo {

public $bar; protected $baz; private $bas; public var1 = "Test"; // String public var2 = 1.23; // Numeric value public var3 = array (1, 2, 3);

} Observe que, como uma variável comum, uma propriedade de classe pode ser declarada e inicializada ao mesmo tempo. Entretanto, a inicialização é limitada à associação de valores (mas não a uma avaliação de expressão). Você não pode, por exemplo, iniciar uma propriedade chamando uma função, o que só pode ser feito de dentro de um construtor.

Constantes, Métodos e Propriedades Estáticos

Juntamente com o PPP, o PHP 5 também implementa métodos e propriedades estáticos. Ao contrário dos métodos e propriedades regulares, os seus correspondentes estáticos existem e são acessíveis como parte de uma classe em si, em oposição ao existente apenas no âmbito de uma das suas instâncias. Isto permite tratá‐las como verdadeiras contêineres de funções e dados interrelacionados o que, por sua vez, é um expediente muito útil para evitar conflitos de nomes. Enquanto o PHP 4 permitia que você chamasse qualquer método de uma classe estática usando o escopo operador de resolução:: (oficialmente conhecido como Paamayim Nekudotayim‐hebraico para Colon "Double"), o PHP 5 introduz uma sintaxe mais rigorosa que apela para o uso da palavra‐chave static para transmitir a utilização de propriedades e métodos como tal. Você deve ter em mente que o PHP 5 é muito rigoroso sobre o uso de propriedades e métodos estáticos. Por exemplo, chamar propriedades estáticas usando a notação de objeto resultará em uma mensagem de erro: class foo {

static $bar = "bat";

Page 7: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

static public function baz() { echo "Hello World"; }

} $foo = new foo(); $foo->baz(); echo $foo->bar; Isso irá mostrar: foo::baz Notice: Undefined property: foo::$bar in PHPDocument1 on line 17 É necessário para a definição de estático seguir a definição de visibilidade, ou seja, se nenhuma definição de visibilidade é declarada, o método ou propriedade é considerado público.

Constantes de Classe

Constantes de classe funcionam da mesma forma que as constantes regulares, exceto que possuem o escopo interno à classe. Constantes de classe são públicas e acessíveis a partir de qualquer escopo. Por exemplo, o seguinte script mostrará Hello World: class foo {

const BAR = "Hello World"; } echo foo::BAR; Constantes de classe têm várias vantagens sobre as constantes tradicionais: uma vez que são encapsuladas em uma classe, elas fazem um código muito mais limpo, e são significativamente mais rápidas do que as declaradas com o construtor define().

Operador de Resolução de Escopo (::)

(Extraído de http://apostilas.fok.com.br/manual_do_php/index.php) O Operador de Resolução de Escopo, também chamado de Paamayim Nekudotayim, ou em termos mais simples, dois pontos duplo, é um token que permite acesso a métodos ou membros estáticos, constantes, e sobrecarregados de uma classe. Quando referenciando esses itens de fora da definição da classe, você usa o nome da classe. No PHP 5.3.0, é possível referenciar o nome da classe usando uma variável. O valor da variável não pode ser uma palavra chave (e.g. self, parent e static). Paamayim Nekudotayim pode parecer de início uma escolha estranha para um dois pontos duplo. No entanto, na hora de escrever o Engine da Zend 0.5 (que provia o PHP3), foi o que a equipe da Zend decidiu. Realmente significa dois pontos duplo ‐ em Hebreu! Exemplo #1 :: de fora da definição da classe class MinhaClasse {

const VALOR_CONST = 'Um valor constante'; } $classname = 'MinhaClasse'; echo $classname::VALOR_CONST; // No PHP 5.3.0 echo MinhaClasse::VALOR_CONST;

Page 8: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

Duas palavras‐chaves especiais self e parent são usadas para acessar membros ou métodos de dentro da definição da classe. Exemplo #2 :: de dentro da definição da classe class OutraClasse extends MinhaClasse {

public static $meu_estatico = 'variável estática'; public static function doisPontosDuplo() { echo parent::VALOR_CONST . "\n"; echo self::$meu_estatico . "\n"; }

} $classname = 'OutraClasse'; echo $classname::doisPontosDuplo(); // No PHP 5.3.0 OutraClasse::doisPontosDuplo(); Quando uma subclasse sobrecarrega a definição de um método do pai, O PHP não chamará o método pai. Fica ao encargo da subclasse chamar o método pai ou não. Isso também se aplica a definições de métodos Construtores e Destruidores, Sobrecarregados e Mágicos também. Exemplo #3 Chamando um método pai

class MinhaClasse {

protected function minhaFuncao() { echo "MinhaClasse::minhaFuncao()\n"; }

} class OutraClasse extends MinhaClasse {

/* Sobrecarrega a definição do pai */ public function minhaFuncao() { /* Mas ainda chama a função pai */ parent::minhaFuncao(); echo "OutraClasse::minhaFuncao()\n"; }

} $classe = new OutraClasse(); $classe->minhaFuncao();

Interfaces e Classes Abstratas

Outro novo recurso adicionado ao PHP 5 é o de interfaces e classes abstratas. Elas são usadas para criar uma série de restrições sobre a concepção básica de um grupo de classes. Uma classe abstrata define essencialmente o esqueleto básico de um tipo específico de entidade encapsulada. Por exemplo, você pode usar uma classe abstrata para definir uma base conceitual de um "carro" como tendo duas portas, um método de fechar ou abrir portas. Classes abstratas não podem ser usadas diretamente, mas devem ser estendidas para que a classe descendente forneça um conjunto completo de métodos. Por exemplo: abstract class DataStore_Adapter {

private $id; abstract function insert(); abstract function update(); public function save() {

if (!is_null($this->id)) { $this->update(); } else { $this->insert();

Page 9: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

} }

} class PDO_DataStore_Adapter extends DataStore_Adapter {

public __construct($dsn) { // ... } function insert() { // ... } function update() { // ... }

} OBS: Você deve declarar uma classe como abstrata, enquanto ela tiver (ou herdar, sem fornecer um corpo) pelo menos um método abstrato. Como você pode ver, neste exemplo, nós definimos uma classe chamada DataStore_Adapter e declaramos dois métodos abstratos chamados insert() e update(). Observe como esses métodos na verdade não têm um corpo ‐ que é um dos requisitos das classes abstratas – e como a própria classe deve ser declarada como abstrata, para que o compilador possa satisfazer os requisitos do analisador sintático. Em seguida, estender DataStore_Adapter em PDO_DataStore_Adapter, que já não é abstrata, porque temos agora um corpo fornecido, tanto para insert() como para update().

Interfaces

Interfaces, por outro lado, são usadas para especificar uma API que uma classe deve implementar. Isto permite‐lhe criar um contrato "comum" que as classes devem implementar com o propósito de satisfazer determinados requisitos lógicos, por exemplo, você poderia usar interfaces para o conceito abstrato de fornecedor de banco de dados em uma API comum que poderia então ser implementada em uma série de classes que fazem interface com SGBDs diferentes. Métodos de Interface não podem conter nenhum corpo: interface DataStore_Adapter {

public function insert(); public function update(); public function save(); public function newRecord($name = null); } class PDO_DataStore_Adapter implements DataStore_Adapter { public function insert() { // ... } public function update() { // ... } public function save() { // ...

Page 10: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

} public function newRecord($name = null) { }

} Se, no exemplo acima, você não definir todos os métodos para uma interface em particular ou todos os argumentos para qualquer método de determinada interface (ou seja, não tiver a mesma assinatura), você vai ver algo como: Fatal error: Class PDO_DataStore_Adapter contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (DataStore_Adapter::save) in //document// on line 27 ou Fatal error: Declaration of PDO_DataStore_Adapter::newRecord() must be compatible with that of DataStore_Adapter::newRecord() in //document// on line 12 É possível implementar mais de uma interface numa mesma classe. Bastando separá‐las por vírgula: class PDO_DataStore_Adapter implements DataStore_Adapter, SeekableIterator { // ... } Lembre‐se: uma classe só pode estender uma classe pai, mas pode implementar várias interfaces. class PDO_DataStore_Adapter extends PDO implements DataStore_Adapter, SeekableIterator { // ... }

Determinando Uma classe de objeto

Muitas vezes é conveniente ser capaz de determinar se um determinado objeto é uma instância de uma determinada classe, ou se ela implementa uma interface específica. Isto pode ser feito usando o operador instanceof: if ($obj instanceof MyClass) {

echo "\$obj is an instance of MyClass"; } Naturalmente, instanceof permite‐lhe inspecionar todas as classes ancestrais de seu objeto, bem como as interfaces.

Exceções

Mesmo que tenham sido um alimento básico da programação orientada a objeto por anos, as exceções apenas recentemente se tornaram parte do arsenal PHP. Exceções fornecem um mecanismo de controle de erro que é mais refinado do que o tratamento de falhas tradicional do PHP, e que permite um grau muito maior de controle. Existem várias diferenças fundamentais entre erros "regulares" de PHP e exceções:

• As exceções são objetos, criados (ou "lançados") quando ocorre um erro;

Page 11: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

• Exceções podem ser tratadas em diferentes pontos na execução de um script, e diferentes tipos de

• Exceções podem ser tratadas por partes separadas de um código de script;

• Todas as exceções não são fatais;

• Exceções podem ser lançadas a partir do método __construct() em caso de falha;

• Exceções alteram o fluxo do aplicativo.

A classe Exception Básica

Como mencionado no parágrafo anterior, as exceções são objetos que devem ser instâncias diretas ou indiretas (por exemplo através de herança) da classe Exceção. Esta última é construída no PHP em si, e é declarada como segue: class Exception {

// The error message associated with this exception protected $message = ’Unknown Exception’; // The error code associated with this exception protected $code = 0; // The pathname of the file where the exception occurred protected $file; // The line of the file where the exception occurred protected $line; // Constructor function __construct ($message = null, $code = 0); // Returns the message final function getMessage(); // Returns the error code final function getCode(); // Returns the file name final function getFile(); // Returns the file line final function getLine(); // Returns an execution backtrace as an array final function getTrace(); // Returns a backtrace as a string final function getTraceAsString(); // Returns a string representation of the exception function __toString();

} Quase todas as propriedades de uma exceção são automaticamente preenchidas para você pelo interpretador, de modo geral, você só precisa enviar uma mensagem e um código, e todas as informações restantes o PHP cuidará para você. Uma vez que uma exceção é uma classe comum (se embutida), você pode estendê‐la e efetivamente criar suas próprias exceções, proporcionando assim seus manipuladores de erro com qualquer informação adicional que sua aplicação requeira.

Lançando Exceções

As exceções são normalmente criadas e acionadas quando um erro ocorre usando a construtor throw: OBS: Embora seja uma prática comum, você não precisa criar o objeto Exception diretamente na expressão throw. if ($error) {

throw new Exception ("This is my error"); }

Page 12: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

As exceções, em seguida, "borbulham" até que sejam tratadas pelo script ou causem uma exceção fatal. O tratamento de exceções é feita usando um bloco try ... catch: try {

if ($error) { throw new Exception ("This is my error");

} } catch (Exception $e) {

// Handle exception } No exemplo acima, qualquer exceção que é lançada dentro do bloco try()será capturada e passada ao código que está dentro do bloco catch(), onde pode ser manipulada como você desejar. Observe como o método catch() da declaração obriga‐nos a informar o tipo de exceção que queremos para o catch(); uma das melhores características das exceções é o fato de que você pode decidir que tipo de exceção capturar. Desde que você é livre para estender a Classe pai Exception, isso significa que diferentes blocos aninhados try ... catch podem ser usados para interceptar e lidar com diferentes tipos de erros: class myException extends Exception { }

try { try { try { new PDO("mysql:dbname=zce"); throw new myException("An unknown error occurred."); } catch (PDOException $e) { echo $e->getMessage(); } } catch(myException $e) { echo $e->getMessage(); } } catch (Exception $e) { echo $e->getMessage();

} Nesse exemplo, temos três blocos aninhados try ... catch, o mais interno só irá capturar objetos PDOException, enquanto que o próximo vai pegar os objetos myException comuns e as regiões mais periféricas irão capturar todas as outras exceções que poderíamos ter perdido. Ao invés de aninhar blocos try ... catch como fizemos acima, você pode também apenas encadear os blocos catch: try {

new PDO("mysql:dbname=zce"); throw new myException("An unknown error occurred."); } catch (PDOException $e) { echo $e->getMessage(); } catch (myException $e) { echo $e->getMessage(); } catch (Exception $e) { echo $e->getMessage();

} Uma vez que uma exceção tenha sido capturada, a execução do script seguirá diretamente após o último bloco catch. Para evitar erros fatais de exceções não capturadas, você poderia envolver toda a sua aplicação em um bloco try ... catch ‐ o que, contudo, poderia ser bastante inconveniente. Felizmente, há uma solução melhor – o PHP nos permite definir uma função "catch-all", que é

Page 13: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

chamada automaticamente sempre que uma exceção não é tratada. Esta função é configurada chamando set_exception_handler(): function handleUncaughtException($e) {

echo $e->getMessage(); } set_exception_handler("handleUncaughtException"); throw new Exception("You caught me!"); echo "This is never displayed"; Note que, devido o manipulador de exceção "catch‐all” ser chamado apenas após a exceção ter borbulhada por todo o script, ele, assim como um bloco abrangente try... catch, é o fim da linha para o seu código. Em outras palavras, a exceção já causou um erro fatal, e a você será apenas dada a oportunidade de lidar com isso, mas não recuperar a partir dela. Por exemplo, o código acima nunca terá uma saída “You caught me!”, porque a exceção gerada irá disparar e causar o manipulador de exceção handleUncaughtException(), fazendo com que o script termine.

OBS: Se você deseja restaurar o manipulador de exceção anteriormente usado, seja ele o padrão de um erro fatal ou outro definido pelo usuário, você pode usar restore_exception_handler().

Exercícios:

Construa um programa com as seguintes características: uma classe Conta abstrata com os métodos abstratos getSaldo(), sacar(valor) e depositar(valor). A seguir, cria duas classes, ContaCorrente e ContaPoupança, sendo que a classe ContaPoupanca deverá estender a classe ContaCorrente, mas contendo um método remunerar(tempo) que aplicará regras de capitalização simples, ou seja, a remuneração incide apenas sobre o montante principal, a uma taxa constante de 10% ao mês. Não se esqueça de definir a classe Conta como abstrata e de inicializar as duas classes (ContaPoupanca e ContaCorrente) com um saldo inicial. Instancie ambas as classes com um valor inicial de R$100,00, exiba os saldos, faça saques e remunere o capital da conta poupança exibindo os valores na tela. Tente fazer sem olhar a resposta abaixo: <?php abstract class Conta {

public $saldo; public abstract function getSaldo(); public abstract function sacar($valor); public abstract function depositar($valor);

} class ContaCorrente extends Conta {

public function __construct($valor) { $this->saldo = $valor;

} public function getSaldo() {

return $this->saldo; } public function sacar($valor) {

if ($valor > $this->getSaldo()) $this->saldo-=$valor; else echo "IMPOSSÍVEL DEBITAR ESSE VALOR";

} public function depositar($valor) {

Page 14: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

if ($valor < 0) echo "Você não pode sacar esse valor!"; else $this->saldo+=$valor;

} } class ContaPoupanca extends ContaCorrente {

private static $taxa = 0.1; //10% ao mês public function __construct($valor) {

$this->saldo = $valor; } public function remunera($tempo) {

$this->saldo += $this->saldo*(self::$taxa * $tempo); }

} $c1 = new ContaCorrente(100); $c2 = new ContaPoupanca(100); echo $c1->depositar(10); echo $c1->getSaldo(); echo "<hr />"; echo $c2->depositar(20); echo $c2->remunera(2); echo $c2->getSaldo(); ?>

Introdução ao MVC com CodeIgniter e PHP

Encontrei esse tutorial sobre MVC que utiliza um framework para permitir maior produtividade no desenvolvimento de software em PHP, conforme exigido na prática profissional da disciplina. Este tutorial foi extraído do endereço http://programadoranonimo.blogspot.com/ e adaptado ao português brasileiro. Este tutorial tem como objetivo abordar o desenvolvimento de aplicações web seguindo uma arquitetura conhecida como arquitetura MVC – Model, View,

Controller. A ferramenta utilizada neste tutorial será o framework CodeIgniter.

O que é Framework?

Em desenvolvimento de software, um framework ou arcabouço é uma abstração que une códigos comuns entre vários projetos de software provendo uma funcionalidade genérica. Um framework pode atingir uma funcionalidade específica, por configuração, durante a programação de uma aplicação. Ao contrário das bibliotecas, é o framework quem dita o fluxo de controle da aplicação, chamado de Inversão de Controle. Ainda, framework é um conjunto de classes que colaboram para realizar uma responsabilidade para um domínio de um subsistema da aplicação. (Extraído da Wikipédia)

O que é o MVC?

O MVC, Model View Controller, é um padrão de desenvolvimento de aplicações, normalmente, mas não forçosamente, web. A implementação de aplicações usando este padrão são feitas com recurso a frameworks, apesar de não ser obrigatória a utilização de um para seguir o padrão.

Camadas e respectivas funções

Page 15: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

• Model: Nesta camada são definidas as regras de acesso e manipulação dos dados, que normalmente são armazenados em bases de dados ou arquivos, mas nada indica que sirva só para alojamento persistente dos dados. Pode ser usado para dados em memória volátil, por exemplo: memória RAM, apesar não se verificar tal utilização com muita freqüência. Todas as regras relacionadas com tratamento, obtenção e validação dos dados devem ser implementados nesta camada.

• View: Esta camada é responsável por gerar a forma como a resposta será apresentada, página web, formulário, relatório, etc.

• Controller: É a camada responsável por responder aos pedidos por parte do usuário. Sempre que um usuário faz um pedido ao servidor esta camada é a primeira a ser executada.

Cadeia de Funcionamento Esta é a cadeia normal de funcionamento deste padrão, em que todas as camadas são usadas, o que nem sempre acontece:

1. O usuário efetua um pedido ao servidor 2. O controller processa o pedido do usuário. 3. O controller efetua uma chamada ao model, para obter ou manipular dados. 4. O model devolve os dados pedidos que serão passados ao view. 5. A view gera a apresentação dos dados, por exemplo: uma página HTML.

Existe a possibilidade, bastante freqüente, de um pedido não precisar invocar o model. Basta querer gerar conteúdo que não necessite de qualquer tipo de dados. Neste caso o controller chamará diretamente o view. Existe também a possibilidade de não ser gerada uma view, por exemplo: o pedido ser uma atualização de dados. Apesar de não ser necessário é recomendado fazê‐lo, as regras de interação obrigam a que se notifique o usuário do sucesso de uma operação, ou seja, a utilização de uma view.

Frameworks Existentes: Existem diversas frameworks que cobrem inúmeras linguagens, algumas só para web e outras mais genéricas:

• PHP: CodeIgniter, CakePHP, Symfony, Zend Framework, etc. • Ruby: Ruby on Rails, etc. • Python: Django, Zope, TuboGears, etc. • Java: J2EE, Spring Framework, etc. • Mono/.NET: Monorail, etc.

Nota: Estes são os frameworks mais populares tendo em conta que são Software Livre, existem outros proprietários, que obviamente não recomendo.

Por que o CodeIgniter?

A resposta curta: porque simplesmente estou utilizando‐o no momento. A resposta comprida: os critérios para o tutorial foram os mesmos para o meu projeto. A questão da linguagem caiu obviamente para o PHP, quer pela sua popularidade em aplicações web, quer pelo fato de ser

Page 16: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

bastante fácil obter serviços de alojamento que o suportem. Quanto ao framework, já utilizei o Symfony e já brinquei com o CakePHP e estou agora a utilizar o CodeIgniter. A escolha deste framework recaiu sobre os seguintes critérios: é simples e com um desempenho bastante bom e a sua abordagem é bastante mais direta que o CakePHP e o Symfony. Esta última é mais complexa, apesar de não ser de todo uma desvantagem. Escolhi o CodeIgniter por ter a "melhor relação custo/qualidade".

Primeiros passos

Para utilizar este framework basta qualquer servidor HTTP com suporte a PHP. É extremamente provável que a aplicação que deseja desenvolver necessite de uma base de dados, estão disponíveis os motores livres PostgreSQL, MySQL e SQLite juntamente com outros proprietários. O primeiro passo é a instalação do framework. Nada mais simples.

• Fazer o download do framework em http://codeigniter.com/download.php • Descomprimir o arquivo. • E copiar o conteúdo do diretório CodeIgniter_x.x.xx para o seu diretório web.

Nota: Evite desenvolver a partir do seu servidor de hospedagem. Se desejar trabalhar num ambiente semelhante a um ambiente real, será boa idéia recorrer a máquinas virtuais. Depois no browser abrir: http://localhost/pasta_de_trabalho/index.php, se tudo correu bem então está pronto a começar a trabalhar. Como ambiente de desenvolvimento recomendo a IDE Eclipse com o plugin PHP Edit (ou mesmo o PDT) ou o NetBeans da SUN também com o plugin PHP. São ferramentas bastante robustas, de fácil utilização, que completam automaticamente o código e que funcionam bem com este framework. Podem fazer download a partir do site oficial e instalar o plugin PHP posteriormente, ou fazer o download personalizado com as funcionalidades que desejar no site yoxos.

Estrutura de diretórios O framework é constituído por um conjunto de diretórios por onde estão espalhados os diversos componentes que o compõem. Ao instalar, verá que existe um diretório de documentação na raiz. Você poderá mantê‐lo ou apagá‐lo, poderá mantê‐lo durante o desenvolvimento da aplicação, mas deverá apagá‐lo quando disponibilizar a aplicação online, a não ser que queira disponibilizar essa documentação online. Existe também um arquivo index.php, este tem obrigatoriamente que existir, pois todos os pedidos à aplicação se iniciam a partir dele. Por fim, temos o diretório system onde existem os seguintes diretórios:

• application: este será o diretório onde fará o desenvolvimento da sua aplicação. Em condições normais será o único a sofrer alterações durante o desenvolvimento.

• cache: o cache do sistema, onde são criados arquivos temporários que permitem o aumento da performance da aplicação.

• codeigniter: o "motor" do framework. • database: controladores de base de dados. • fonts: tipos de letra. • helpers: coleções de funções de auxilio ao desenvolvimento que, por exemplo, poderão

ajudar a criar elementos de uma página de uma forma mais simples. • language: arquivos com termos usados pela framework numa determinada língua.

Instalação do Português padrão.

Page 17: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

• library: biblioteca com as classes de referência que podem ser utilizadas no desenvolvimento da aplicação.

• logs: logs de sistema • plugins: similar aos helpers, só que em vez de uma coleção de funções os plugins apenas

disponibilizam uma função. • scaffolding: motor de scaffolding. Permite a gerar automaticamente páginas de

visualização, criação, edição e eliminação de dados a partir de tabelas da base de dados. Esta ferramenta apenas deve ser utilizada durante o desenvolvimento, pois não oferece qualquer garantia de segurança. Este modelo de scaffolding deixou de ser oficialmente suportado e será substituído, pelo que não deverá ser abordado para já nesta série de tutoriais.

Dentro da pasta application temos um conjunto de diretórios orientado para o desenvolvimento da aplicação. Os diretórios helpers, languages e libraries são equivalentes aos que encontramos no diretório system, mas neste caso destinam‐se a componentes criados especificamente para o seu projeto. Os diretórios restantes são os seguintes:

• config: arquivos de configuração. • controllers: local onde criará os seus controllers. • errors: páginas de erro personalizadas, como por exemplo o famoso 404‐Not Found • hooks: extensões ao CodeIgniter, onde poderá criar funções ou classes que serão

executadas em determinados momentos do fluxo de processamento da aplicação. • models: local onde criará os seus models. • views: local onde criará as suas views.

Olá mundo

Para variar vamos começar com a criação de um programa Olá Mundo. A maneira mais simples de fazê‐lo é utilizar apenas um controlador. Vá à pasta controllers e crie um arquivo chamado primeiro.php e edite‐o. Nele escreva o seguinte código:

<?php class Primeiro extends Controller { //em PHP4: function Primeiro() function __construct() { parent::Controller(); } function index() { echo 'Olá Mundo' } } ?>

Se digitar no seu web browser o endereço http://localhost/index.php/primeiro obterá uma página com o texto “Olá Mundo”. O exemplo começa pela declaração de uma classe que herda as características de classe do CodeIgniter Controller, todos os controllers são subclasses de Controller, o nome da classe e do arquivo são iguais, a única diferença é que o nome da classe deve começar sempre com maiúscula. Depois temos duas funções: a função Primeiro() é o construtor da classe, que neste caso apenas chama o construtor da sua

Page 18: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

superclasse, este pode ser usado para carregar qualquer tipo de componente do sistema; a segunda função é uma atividade do controlador, normalmente todos os controladores têm uma função index que é chamada sempre que esse controlador é invocado sem que seja invocada qualquer função. Vamos acrescentar mais uma função ao nosso controlador:

<?php class Primeiro extends Controller { (...) function opiniao() { echo 'Estou a gostar muito desta ferramenta'; } } ?>

OBS: o PHP 5 utiliza o construtor __construct(). Esta função é similar à anterior, apenas serve para demonstrar o funcionamento dos endereços. Neste caso, para invocar esta atividade do controlador deverá digitar o endereço: http://localhost/index.php/primeiro/opiniao

A estrutura padrão dos endereços é: ...index.php/Nome do Controlador/Atividade/Informação complementar

Caso não seja especificada nenhuma atividade, será sempre executada a função index, como no primeiro exemplo, pelo que deverá existir sempre um index em cada controlador. OBS: Agora, é bom configurar o arquivo config.php na pasta config dentro da pasta application. Nela, existe uma linha $config['base_url'] = "http://example.com". Altere‐a para o endereço que você vai utilizar em seu aplicativo. Por exemplo: “http://localhost/pasta_de_trabalho”. Views As views são arquivos PHP que contêm código HTML e chamadas PHP responsáveis pela apresentação dos dados. No exemplo anterior eram os controladores que apresentavam qualquer conteúdo na página, o que não é prático nem segue a norma MVC, pelo que vamos fazer algumas alterações. Primeiro vamos acrescentar uma nova view, no diretório views crie o arquivo mensagem.php com o seguinte conteúdo: <html> <head> <title><?php echo $title ?></title> </head> <body> <h1><?php echo $message ?></h1> </body> </html>

Page 19: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

Esta view será invocada por ambos os controladores e como podemos observar serão passadas

duas variáveis: title que definirá o título a aparecer na janela do browser e message que terá a mensagem que aparecerá na página web. Para utilizar a view vamos alterar ambas as ações do controlador. <?php class Primeiro extends Controller { //em PHP4: function Primeiro() function __construct() { parent::Controller(); } function index() { $data['title']='Primeiro Exemplo'; $data['message']='Olá Mundo!'; $this->load->view('mensagem',$data); } function opiniao() { $data['title']='A minha opinião'; $data['message']='Estou a gostar muito desta ferramenta'; $this->load->view('mensagem',$data); } } ?>

Agora o funcionamento ficou ligeiramente alterado. Para passar dados a uma view é necessário criar um vetor associativo em que o índice terá correspondência a uma variável com o mesmo nome na view. A última linha de cada atividade é uma chamada à view onde o primeiro parâmetro corresponde ao nome do arquivo da view (a extensão PHP pode ser omitida), e o segundo corresponde à estrutura com os dados a serem passados. Não há qualquer obrigação de passar dados para uma view, pelo que nestes casos deverá apenas invocar a view apenas com o primeiro parâmetro. Para uma view podem ser passados dados de qualquer tipo, sejam eles numéricos, texto, objetos ou outras estruturas de dados. O próximo exemplo demonstra como passar um vetor para a view e como este normalmente é tratado. Crie uma nova view chamada topics.php com o seguinte conteúdo: <html> <head> <title>Uma lista de tópicos</title> </head> <body> <ul> <?php foreach($topics as $topic): ?> <li><?php echo $topic ?></li> <?php endforeach ?> </ul> </body> </html>

Aqui a única diferença é que é usado um ciclo foreach para escrever cada um dos elementos na página. Para pôr esta view para funcionar necessitamos criar uma atividade no nosso controlador que o invoque, por isso vamos adicionar a função topics() no arquivo primeiro.php:

Page 20: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

function topics() { $data['topics'] = array('Model', 'View', 'Controller'); $this->load->view('topics', $data); }

Nada mais simples. No diretório views é possível criar subdiretórios para organizá‐las. Para invocar essas views deverá incluir o nome do diretório na sua chamada: $this->load->view('directory/topics');

E assim terminamos este capítulo, no próximo serão abordados o uso de bases de dados e os modelos.

Acesso a dados

Depois de termos dado uma visão global ao padrão MVC e de dar os primeiros passos com o framework CodeIgniter, abordaremos uma parte também importante de uma aplicação web: o acesso a bases de dados.

Criação da base de dados e configurar o acesso

Ao contrário de alguns frameworks, como por exemplo, o Symfony, o Django, etc., o CodeIgniter não possui nenhum mecanismo próprio para criação de bases de dados, à semelhança do que acontece no Ruby on Rails ou no CakePHP, motivo pelo qual teremos que criá‐lo. O CodeIgniter segue um padrão de acesso a dados conhecido como Active Record que será demonstrado mais à frente. Para este capítulo, apenas iremos utilizar a seguinte tabela utilizando o MySQL:

CREATE TABLE `users` ( `id` int(11) NOT NULL auto_increment, `username` varchar(20) character set latin1 NOT NULL, `passwd` varchar(40) character set latin1 NOT NULL, `salt` varchar(40) character set latin1 NOT NULL, `email` varchar(100) character set latin1 NOT NULL, PRIMARY KEY (`id`) );

Agora vamos configurar o acesso à base de dados no CodeIgniter, dentro do diretório application/config editem o arquivo database.php: $active_group = "default"; $active_record = TRUE; $db['default']['hostname'] = "localhost"; $db['default']['username'] = "root"; $db['default']['password'] = ""; $db['default']['database'] = "ads01"; $db['default']['dbdriver'] = "mysql"; $db['default']['dbprefix'] = ""; $db['default']['pconnect'] = TRUE; $db['default']['db_debug'] = TRUE; $db['default']['cache_on'] = FALSE; $db['default']['cachedir'] = ""; $db['default']['char_set'] = "utf8"; $db['default']['dbcollat'] = "utf8_general_ci";

Page 21: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

O arquivo em si não tem muito que saber. Basta alterar o valor de cada elemento com os dados

respectivos. Para seguir este tutorial será necessário ter a variável $active_record fixada como TRUE. O passo seguinte será configurar o acesso à classe de base de dados. Isto pode ser feito de dois modos: ativar o carregamento automático da classe ou carregá‐la no construtor de cada Controller ou Model: //---Carregamento "Manual"--- //em cada controlador ou modelo invocar //$this->load->database() class User extends Controller { //em PHP4: function Nome() function __construct() { parent::Controller(); $this->load->database(); } } //---Carregamento automático //para carregamento automático editar config/autoload.php //e adicionar 'database' ao array $autoload['libraries'] $autoload['libraries'] = array('database');

Para verificar se a conexão à base de dados está funcionando basta executar o seu browser e abrir o url da sua aplicação. Se não foi informado algum erro, então está tudo ok. Nota: A escolha de utilização de carregamento automático ou não classes está dependente do tipo de projeto. Se for uma classe utilizada por todos os controladores recomenda‐se o carregamento automático de modo a poupar algum esforço. Se essa classe apenas for utilizada por algumas funcionalidades então recomendo que se faça o carregamento apenas quando necessárias para evitar sobrecarregar os controladores com material desnecessário.

Ler registros da base de dados

A exibição de dados é certamente a tarefa mais comum em aplicações web. Para demonstrar como realizar este tipo de tarefas vamos criar duas atividades num controlador User em controllers/user.php:

• user/all • user/show/$id

Para testar este exemplo recomendo que introduzam alguns dados na tabela users: <?php class User extends Controller { function __construct() { parent::Controller(); $this->load->helper('url'); } function all() { //selecciona todos os registros de users

Page 22: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

$data['list']=$this->db->get('users'); //envia a lista de dados para a view $this->load->view('user/all',$data); } function show() { //vai buscar o id ao url, 3º elemento //se não for escrito retorna 0 $username = $this->uri->segment(3,0); if($username == 0) { //se o id não foi fornecido redireciona redirect('user/all'); } else { $result = $this->db->get_where( 'users', array('username' => $username)); //selecciona a única linha do resultado $data['user'] = $result->row(); $this->load->view('user/show',$data); } } } ?>

E agora as duas user/all e user/show: user/all: <h1>Lista de usuários</h1> <table> <tr> <th>Username</th> <th>Email</th> <th></th> </tr> <?php foreach($list->result() as $user): ?> <tr> <td><?php echo $user->username ?></td> <td><?php echo $user->email ?></td> <td><?php echo anchor('user/show/'.$user->username);?></td> </tr> <?php endforeach ?> </table>

user/show: <p><b>Username:</b> <?php echo $user->username ?></p> <p><b>E-mail:</b> <?php echo $user->email ?></p>

Os métodos mais importantes para este exemplo são:

• $this->db->get('tabela'): Devolve todos os dados da tabela (SELECT * FROM tabela)

Page 23: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

• $this->db->get_where('tabela', critérios): seleciona todos os registro que correspondam a um critério.

Os registros devolvidos são armazenados numa estrutura em memória da qual se pode extrair cada um deles como instância de um objeto Active Record, como neste exemplo, ou alternativamente num array associativo. Neste exemplo foram usados dois métodos: result() e row(). O método result(), usado na view user/all gera uma lista de objetos row, cada um deles representa um registro. O método row() extrai diretamente uma linha, o que é muito útil para casos como este em que a consulta à base de dados devolve uma única linha, caso devolva mais que uma linha o método row() devolverá apenas a primeira linha. Neste exemplo utilizou‐se o helper url. Esse fornece, entre outras, a função anchor que nos permite criar hyperlinks de forma dinâmica para outras funcionalidades da nossa aplicação. No exemplo acima podemos ver que esta é utilizada para criar ligações para a página show de cada registro. Outra função a destacar que utilizamos é a função uri->segment que extrai elementos da nossa url, neste caso o username. O segundo parâmetro é opcional e indica o valor por omissão caso se invoque essa funcionalidade sem fornecer o username.

Modelos Como foi explicado no primeiro tutorial, no padrão MVC o Model é responsável pela abstração do acesso a dados. O que se passa no CodeIgniter é que o padrão Active Record já faz isso de uma forma mais geral. É possível criar um projeto sem ter que implementar classes do tipo modelo, mas para casos mais específicos, como consultas mais complexas, é recomendado implementar essas funções numa classe Model. Podemos reestruturar o exemplo anterior tendo em conta os seguintes aspectos:

• Estamos requisitando à tabela todos os campos de um registro quando apenas utilizamos dois deles

• Podemos criar métodos para obter os dados prontos a ser exibidos, encurtando o tamanho dos nossos controladores

Para isso vamos criar uma classe user_model.php no diretório models: <?php class User_model extends Model { function getDisplayableByUsername($username) { //indica os campos $this->db->select('username, email'); $result = $this->db->get_where( 'users', array('username' => $username)); return $result->row(); } function getAllDisplayable() { $this->db->select('username, email'); $result = $this->db->get('users'); return $result->result(); } }

Page 24: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

Neste exemplo, criamos duas funções que retornam os resultados apenas com os dados que desejamos exibir. O método select da classe db encarrega‐se de definir os campos a retornar pela próxima consulta à base de dados. Agora falta‐nos alterar o controlador para utilizar o model. <?php class User extends Controller { function __construct() { parent::Controller(); $this->load->helper('url'); $this->load->model('user_model'); } function all() { //selecciona todos os registros de users //a ser exibidos $data['list'] = $this->user_model->getAllDisplayable(); $this->load->view('user/all',$data); } function show() { //vai buscar o id ao url, 3º elemento //se não for escrito retorna 0 $username = $this->uri->segment(3,0); if($username == 0) { redirect('user/all'); } else { $data['user'] = $this->user_model->GetDisplayableByUsername($username); $this->load->view('user/show',$data); } } } ?>

Para completar, como o método GetAllDisplayable() já retorna uma lista result, devemos ir ao código da view user/all e remover a chamada ao método result() no ciclo foreach para que tudo funcione devidamente.

Inserir dados, Formulários e Validação

No que diz respeito à validação, será usado o novo sistema form_validation introduzido na versão 1.7.0. Em qualquer página web com validação de dados existe o seguinte ciclo de validação:

1. Pedir os dados ao usuário; 2. Verificar os dados; 3. Caso os dados não sejam válidos exibir erros e voltar ao ponto um; 4. Tratar os dados.

Page 25: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

Começando pela solicitação de dados, vamos criar uma view user/register.php com o seguinte conteúdo: <?php echo validation_errors() ?> <?php echo form_open('user/register') ?> <fieldset> <label for="username">Usuário: </label> <input type="text" id="username" value="" /> <label for="password">Palavra-Passe:</label> <input type="password" id="password" value="" /> <label for="confirm">Confirmar:</label> <input type="password" id="confirm" value="" /> <label for="email">E-mail</label> <input type="text" id="email" value="" /> </fieldset> <input type="submit" value="Enviar" /> </form>

A view acima é um formulário típico em PHP/HTML. Na primeira linha serão impressas as mensagens de erro caso a validação dos dados falhe. Recorre‐se também à função form_tag para gerar uma tag form que chamará o controlador responsável por validar e armazenar os dados. Agora para armazenar os dados resta‐nos criar o controlador para o efeito. Mas antes disso vamos preparar a nossa classe modelo para guardar este tipo de dados. Lembre‐se que estamos a criar um formulário para registro de usuários e dados sensíveis como a password não serão armazenados no formato em que são inseridos. A palavra passe será transformada antes de ser armazenada recorrendo à função de hashing sha1 utilizando uma chave salt para impedir a obtenção da senha através de dicionários de hash conhecidos. Ao modelo user_model.php serão acrescentados os seguintes métodos:

<?php private function hashPassword($password) { //gera uma string salt aleatória $data['salt'] = sha1(rand()); //gera o hashing da password $data['password'] = sha1($data['salt'].$password); return $data; } function register() { $data['username'] = $this->input->post('username'); $hash = $this->hashPassword($this->input->post('passwd')); $data['passwd'] = $hash['password']; $data['salt'] = $hash['salt']; $data['email'] = $this->input->post('email'); $this->db->insert('users', $data); } ?>

O método register guarda os dados, depois de codificar a password. Usando o método insert do Active Record a inserção de dados não poderia ser mais simples, basta um array associativo em que o índice corresponde ao nome do campo na tabela e depois passá‐lo como argumento da função insert. Para obter os dados enviados pelo formulário podem usar o

método $this->input->post('nome') ou acessar diretamente ao respectivo elemento no

Page 26: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

array post: $_POST['nome']. O método hashPassword é responsável apenas por gerar um

hash e um salt para a senha. Por fim, no controlador user, vamos criar um método register que, neste exemplo, será responsável por criar as regras e executar o ciclo de validação: <?php function register() { //definição da lista de regras a aplicar $config=array( array( 'field' => 'username', 'label' => 'Nome de Usuário', 'rules' => 'required|min_length[4]|max_length[20]' ), array( 'field' => 'passwd', 'label' => 'Palavra Passe', 'rules' => 'required|min_length[6]|matches[confirm]' ), array( 'field' => 'confirm', 'label' => 'Confirmação de Palavra Passe', 'rules' => 'required' ), array( 'field' => 'email', 'label' => 'E-mail', 'rules' => 'required|valid_email' ) ); //atribui a lista de regras à próxima execução da validação $this->form_validation->set_rules($config); //Teste de validação de dados if(($this->form_validation->run())==FALSE) { //caso a validação não tenha tido sucesso //ou ainda não foi invocada $this->load->view('user/register'); } else { //se a validação teve sucesso $this->user_model->register(); //redirecciona para uma página de sucesso redirect('user/success'); } } ?>

Nesse exemplo, recorremos ao método de criar um array com todas as regras de validação a aplicar. Nesse array, cada elemento possui três campos:

• field: possui o nome do campo a avaliar, deverá obrigatoriamente corresponder ao id do elemento do formulário que fornecerá esses dados.

• label: contém uma identificação do campo, compreensível pelos usuários, a aparecer na mensagem de erro.

Page 27: Introdução à Linguagem PHP · PDF fileFundamentos de POO Enquanto o objetivo deste capítulo não é fornecer um guia aos conceitos da Programação Orientada a Objetos (POO), é

• rules: aqui são declaradas as regras a ser aplicadas ao campo, as mais comuns são:

required, campo obrigatório; min_length/max_length, definem os limites de tamanho em caracteres dos dados inseridos; valid_email, endereço de correio eletrônico válido, etc.

A estrutura if no exemplo garante a execução do ciclo de validação. Na primeira chamada ao controlador, invocada pelo usuário, a validação falha sempre sem qualquer erro, por isso é exibida a view com o formulário. O usuário ao enviar os dados faz com que o controlador seja de novo invocado e a validação executada. Se falhar será reexibido o formulário com as respectivas mensagens de erro. Caso os dados estejam corretamente inseridos, serão guardados na base de dados. Após o armazenamento o controlador os redireciona para uma página de sucesso que não foi listada neste exemplo, dada a sua simplicidade deixo‐a ao critério de cada um.