Artigo Clube Delphi 102 - Conceitos OO e novidades do PHP

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (0)  (0)

Artigo da Revista Clube Delphi Edição 102.

Esse artigo faz parte da revista Clube Delphi Edição 102. Clique aqui para ler todos os artigos desta edição

PHP

Orientação a Objetos no PHP

Conheça conceitos e novidades importantes

 

Neste artigo veremos

·         Orientação a Objeto;

·         Dicas sobre como trabalhar com objetos no PHP;

·         Novidades para a versão 5.3 do PHP.

Qual a finalidade?

·         Apresentar os conceitos mais comuns sobre orientação a objetos aplicados ao PHP.

Quais situações utilizam esses recursos?

·         Construir sistemas Web usando objetos ajuda o desenvolvedor a evitar replicação de código, já que uma classe ou várias classes podem ser aproveitadas em vários projetos.

 

Resumo do DevMan

Trabalhar com orientação a objetos tornou-se uma prática comum para vários desenvolvedores, por isso o presente artigo irá demonstrar algumas das características desta metodologia aplicada ao PHP, dicas e cuidados a respeito do funcionamento do modelo de objetos implementado no PHP e quando possível um paralelo com a linguagem Delphi.  Além disso, descreverá as novidades referentes a objetos para a versão 5.3 que promete ser uma das mais proeminentes da linguagem.

 

Orientação a objetos é uma metodologia comum hoje e presente na maioria das linguagens de programação. Com o PHP não poderia ser diferente. A partir da versão 5, a linguagem apresentou grandes mudanças em sua estrutura interna para suportar esta técnica de forma mais consistente. Neste artigo apresentaremos alguns dos conceitos que foram adicionados nesta versão e as novidades para versão 5.3. Para aqueles que estão começando agora, é feita uma apresentação rápida dos três conceitos clássicos pertinentes a orientação a objetos, são eles: herança, polimorfismo e encapsulamento. O presente artigo não tem o objetivo de explorar ou esgotar todos os conceitos da orientação a objetos como classes, propriedades, etc, mas servir como uma revisão geral sobre este tema aplicado ao PHP.

Encapsulamento

O conceito de encapsulamento é uma característica da orientação a objetos que permite que você oculte partes, independente da sua implementação. Assim, o encapsulamento permite que você construa partes ocultas do software que realizem uma funcionalidade e ocultem sua construção do mundo exterior. Isso se assemelha muito a uma caixa preta aonde você só tem acesso interface(método), porém não ao seu código.

Se compararmos ao Delphi for Win32, temos como exemplo de encapsulamento componentes, dlls, bpls e outros conjuntos de arquivos que podem ter parte de suas rotina ocultas.

Herança

Já o termo herança se assemelha ao mesmo conceito que existe no mundo real. A palavra se refere ao conceito de receber algo. Herança pode ser entendida como um mecanismo que permite construir uma nova classe com base em uma classe previamente existente, onde a nova classe herda automaticamente todos os atributos, comportamentos e implementações da sua classe Pai.

Polimorfismo

Polimorfismo significa muitas formas ou algo que pode mudar de forma. Em termos de programação, isso significa que podemos ter um mesmo método sendo executado de maneiras diferentes. Esse polimorfismo pode ser implementado em uma herança que permite que uma classe filha sobreponha o(s) método(s) de sua classe pai ou até mesmo dentro de uma mesma classe que apresente variações de um determinado método.

Em outras palavras, o polimorfismo pode ser usado para criar classes e objetos filho, que tenham algumas das funcionalidades e atributos modificados após a sua criação.

Definindo classes e criando objetos no PHP

Uma definição rápida para o conceito de classe é que ela se apresenta como um molde para criação de objetos definindo seus métodos e atributos. Já um objeto é uma instância desta classe, e que pode alterar os seus atributos e fazer o uso de seus métodos. Fazendo um exercício rápido para entender esse conceito pense na palavra carro, sua mente automaticamente projetou algo como tendo 4 rodas, motor, portas, etc. Essa projeção, que recebe o nome de abstração, definiu uma forma do que conhecemos como carro, e podemos chamar de classe. Agora imagine um estacionamento, ali teremos várias instâncias da classe carro, pois cada carro segue o padrão: 4 rodas, motor, portas, etc. Contudo cada carro tem características diferentes, porém todos pertencem a mesmas origem (classe). Isso é verdade porque nesse estacionamento podem existir carros com duas ou quatro portas, com as mais variadas cores, porém todos continuam sendo carros!

Trazendo isso para o contexto do PHP, para criar uma classe na linguagem basta fazer uso da palavra chave class e após a escrita deste comando deve-se escrever o nome da classe. Esse nome pode ser qualquer nome, contanto que não seja uma palavra reservada do PHP. Após o nome dela coloca-se um par de chaves {} que irá delimitar o corpo desta classe. Uma pseudo variável chamada $this fica disponível ao desenvolvedor quando este precisar chamar um método e/ou atributo dentro do contexto do objeto. 

Para exemplificar melhor e entendermos o que foi dito, vamos criar um exemplo simples. Crie três scripts separados com os nomes Imposto.php, ISS.php e resultados_classes.php. Digite o código de cada um de acordo com as Listagens 1, 2, e 3 e salve-os dentro do mesmo diretório. Use o Bloco de Notas do Windows ou qualquer outro editor de sua preferência, como o Dreamweaver da Adobe, por exemplo. 

Comecemos analisando a pseudo variável $this no PHP, que tem a mesma função de self no Delphi. Veja os códigos das listagens mencionadas e o resultado na Figura 1. Perceba que criamos uma classe chamada Imposto na Listagem 1. A palavra reservada $this nas funções calcularImposto e getAliquota, fazem referência a variável $aliquota da classe Imposto. Já na Listagem 2 estamos estendendo, ou seja, herdando da classe Imposto e criando uma nova classe, a ISS. Isso é um exemplo claro de herança como já explicado anteriormente. Usamos a função require_once() para importar o código da classe Imposto que foi salva no arquivo Imposto.php. Perceba o uso da palavra reservada extends para estender a classe Imposto.

 

class ISS extends Imposto{[…]

 

Nota: O PHP também tem a palavra chave self, porém seu significado refere-se ao contexto de classe e não de um objeto em específico. Vale destacar também que há permissão para declarar mais de uma classe em um mesmo arquivo fonte.

 

Listagem 1. Criando a classe Imposto

class Imposto{

  private $aliquota;

   public function calcularImposto($preco, $aliquota) {

     $this->aliquota = $aliquota;

     return ($preco*$this->getAliquota())/100;

   }

   public function getAliquota() {

     return $this->aliquota;

   }

}

?>

Listagem 2. Criando a classe ISS que estende (Herda) de Imposto

require_once('Imposto.php');

class ISS extends Imposto{

  public function calcularImposto($preco, $aliquota){

     if (is_null($aliquota)){

        $aliquota = 5;

     }

     return parent::calcularImposto($preco, $aliquota);

   }

}

?>

 

A Listagem 3 é ainda mais interessante, vejamos. Vemos um exemplo de criação de objetos. Para criar um novo objeto no PHP faz-se uso da palavra chave new. Repare que na função imprimeInstancia há uma indução de tipo, onde um objeto Imposto é esperado. Ali está um exemplo do polimorfismo, já que a função espera qualquer objeto, contanto que seja do tipo Imposto. Note que o método funciona tanto para a instância de ISS quanto para Imposto, já que ISS é um tipo de Imposto.

 

Listagem 3. Criando objetos e um exemplo de polimorfismo na prática

require_once('Imposto.php');

require_once('ISS.php');

function imprimeInstancia(Imposto $imposto){

  if ($imposto instanceof ISS){

     echo "O objeto passado pertence a classe ISS
";

   }elseif(

    $imposto instanceof Imposto){

     echo "O objeto passado pertence a classe Imposto
";

   }else{

     echo "Objeto sem classe
";

   }

}

$imposto = new ISS();

echo "ISS de um produto com valor de 15: " .

  $imposto->calcularImposto(15, null)."
";

imprimeInstancia($imposto);

$imposto = new Imposto();

echo "Imposto de um produto com valor de 10 e taxa de 8.5%: " .

  $imposto->calcularImposto(10, 8.5)."
";

imprimeInstancia($imposto);

?>

 

Figura 1. Resultado do código da Listagem 3

 

Execute o arquivo resultados_classes.php no seu browser preferido e veja que nosso script funciona perfeitamente. Em outras palavras: utilizando a palavra reservada class, criamos uma classe chamada Imposto e depois construímos o seu corpo dentro do escopo delimitado pelo par de chaves. Métodos em uma classe PHP podem ser codificados utilizando a notação:

 

visibilidade function [(parâmetros)]

 

Vale destacar que, ao contrário do Delphi, não há a necessidade de especificar o tipo de retorno do método ou mesmo se ele não irá retornar nada. Você sabe se um método de uma classe irá retornar algo ou não, se este apresentar dentro do seu escopo a palavra chave return. Além disso, a assinatura de um método pode variar. Se o seu propósito for para representar métodos de classe adiciona-se ainda static ou se este delegar a sua implementação pode-se usar abstract. Sobre atributos a sua codificação é mais simples, geralmente coloca-se o operador de visibilidade acrescido do nome do atributo, também não é necessário indicar o tipo de dado que será armazenado. Com o uso da palavra chave private, que restringiu o acesso ao atributo $aliquota, somente para a própria classe aplicamos o conceito de encapsulamento. Há como especificar restrições de visibilidade em classes, e veremos mais adiantes nesse artigo.

 

Nota: Apesar de não ser necessário indicar a visibilidade em um método ou atributo, seu uso é altamente recomendável.

 

Nota: A palavra reservada instanceof  é usada para determinar se uma variável do PHP pertence a determinada classe. Do lado esquerdo fica a variável que se quer avaliar e do lado direito a classe.

 

Construtores e Destrutores

Antes da versão 5 do PHP, o nome do construtor era o mesmo nome classe. A partir dessa versão, tem-se a introdução da palavra chave __construct. Vale ressaltar que o PHP só permite um construtor por classe. Caso não seja informado nenhum, a linguagem cria um construtor padrão. Para fazer chamadas ao construtor de uma classe Pai, por exemplo, é utilizada a palavra chave parent. Ex:

 

parent::__construct

 

O método destrutor, de um objeto será chamado assim que todas as referências a um objeto particular forem removidas da memória, quando o objeto for explicitamente destruído ou ainda em uma seqüência de destruição de objetos. Para definir um método destrutor em uma classe, deve-se usar a palavra chave __destruct. Assim como no construtor, para chamar o método destrutor de uma classe Pai, basta novamente fazer uso de parent seguido do método __destruct. Experimente criar um novo script e digitar o código da Listagem 4 que mostra um exemplo de uma classe com um construtor e destrutor definido. Execute-o e veja o resultado. Nesse script, estamos criando duas variáveis privadas, ou seja, de uso somente da classe Pessoa e fazendo referência a elas no método __construct() da classe. Em seguida, atribuímos a variável $pessoa a criação de um objeto Pessoa(instância). O método __construct() então associa a nome e idade o valor recebido em seus dois parâmetros, $nome e $idade, porém a impressão das informações são feitas somente no método __destruct().

 

Listagem 4. Métodos construtores e destrutores em uma classe

class Pessoa{

  private $nome;

   private $idade;

   public function __construct($nome, $idade){

     $this->nome = $nome;

     $this->idade = $idade;

  }

   public function __destruct(){

     echo "Meu nome: ".$this->nome.". Tenho: ".$this->idade." anos";

  }

}

$pessoa = new Pessoa("Fulano", "21");

?>

 

Se você executar o script verá que funciona normalmente, pois assim que a classe é criada a mesma é destruída (ao final da leitura do script pelo browser) mostrando então o nome e idade passados.

 

Nota: O operador :: (dois pontos) é o operador que permite acesso a membros estáticos e constantes de classes.

 

Perceba que até aqui utilizamos a palavra reservada public em todas as classes. A visibilidade de um atributo ou método pode ser definida utilizando na sua declaração as palavras-chave: public, protected ou private. Itens declarados como public podem ser acessados por todo mundo. Protected limita o acesso a classes herdadas (e para a classe que define o item). Private limita a visibilidade para apenas a classe que define o item (método/atributo). O PHP não tem o conceito de published do Delphi.

 

Classes abstratas e interfaces

Interfaces de objetos são classes especiais que podem ser definidas no código. Elas especificam um ou mais métodos e seus respectivos parâmetros, mas ao contrário de classes tradicionais, não os codificam. Toda interface é definida com a palavra reservada interface, seguida do seu nome que possui as mesmas regras de definição do nome de uma classe e sua respectiva lista de métodos e parâmetros. Uma classe que deseja implementar uma interface deve usar a palavra chave implements na sua declaração.

 

Nota: O PHP não tem herança múltipla. Para simular este conceito, a linguagem faz uso de interfaces. Uma interface tem todas as assinaturas de métodos como públicos mesmo que o desenvolvedor não especifique isso.

 

Já o conceito de classes abstratas foi introduzido na versão 5. A explicação de seu funcionamento é muito parecida com o de uma interface, contudo esse tipo de classe tem algumas características particulares como:

·         Não é permitido instanciar classes abstratas, se isto for feito irá causar um erro;

·         Qualquer classe que contiver pelo menos um método que seja abstrato deverá ser declarada abstrata. Para isso o uso da palavra reservada abstract se faz necessário tanto na declaração do nome da classe como na assinatura do método;

·         Classes abstratas podem conter tanto métodos abstratos que contenham somente a assinatura do método, como métodos concretos;

·         Qualquer classe que estender de uma classe abstrata deve implementar os métodos abstratos contidos nesta;

·         Quando uma classe abstrata implementa uma interface, ela não precisa codificar seus métodos deixando isso a classe concreta que estender dela, conforme já comentando no tópico de interfaces.

 

Veja um exemplo do uso de interfaces no código a seguir e nas Listagens 5 e 6 . O resultado, podemos ver na Figura 2.

 

interface ImpostoConta{

  const CPMF = 0.38;

  public function calcularImposto($valor, $taxa);

}

?>

 

Aqui definimos uma interface que define um método para calcular imposto, toda a classe que implemente uma interface deve implementar os métodos constantes nesta. A exceção se dá se a classe for declarada abstrata assim a implementação fica a cargo da primeira classe concreta da hierarquia de classes.

 

Listagem 5. Classe abstrata simulando operações de uma conta

abstract class Conta{

  protected $saldo;

  public function __construct($saldo){

     $this->saldo = $saldo;

  }

  public abstract function sacar($valor);

  public abstract function depositar($valor);

  public abstract function mostraSaldo();

}

?>

 

Definimos um classe base denominada Conta e que possui uma modelagem das operações normalmente encontradas numa conta de banco que são sacar, depositar e mostrar o saldo.

 

Listagem 6. Classe ContaPoupanca que estende de Conta e implementa ImpostoConta

require_once('Conta.php');

require_once('ImpostoConta.php');

class ContaPoupanca extends Conta implements ImpostoConta {

  public function __construct($saldo) {

     parent::__construct($saldo);

   }

   public function sacar($valor){

     $this->saldo = $this->saldo - ($valor + $this->

      calcularImposto($valor, ImpostoConta::CPMF));

   }

   public function depositar($valor) {

     $this->saldo = $this->saldo + $valor;

  }

   public function mostraSaldo() {

    echo "Saldo da conta: ".$this->saldo."
";

  }

   public function calcularImposto($valor, $taxa) {

     return round((($valor*$taxa)/100),2);

   }

}

$poupanca = new ContaPoupanca(100);

$poupanca->sacar(10);

$poupanca->mostraSaldo();

$poupanca->depositar(10.04);

$poupanca->mostraSaldo();

?>

 

Por último criamos a classe ContaPoupanca e  implementamos todos os métodos tanto da interface como da classe pai. Usamos a função round para arredondar o cálculo do imposto em duas casas no método para calcularImposto. O leitor pode reparar também que no código da classe ContaPoupanca os métodos herdados da classe Conta tiveram a palavra reservada abstract retiradas de sua assinatura, já que a classe iria implementar os mesmos.

 

Figura 2. Resultado do código da Listagem 6

 

Outros conceitos úteis

Vamos continuar listando mais algumas novidades da versão 5 referente a objetos. Uma delas foi a introdução de constantes de classe e sua declaração, que é feita através da palavra chave const. Para acessar constantes de classe fora do escopo dela a seguinte notação é utilizada:

 

NomeClasse::Constante

 

E já dentro da classe via a notação:

 

 self::Constante

 

A palavra reservada self também pode ser utilizada para se referenciar a própria classe. Veja o exemplo da Listagem 7, onde é feito o uso de constantes de classe e self, o resultado é visto na Figura 3. Para codificar constantes em uma classe utilize const.

 

Listagem 7. Uso da palavra chave self e static além de constantes de classe

class Calendario {

  const NOME = "Classe Calendario";

}

class DiasDaSemana extends Calendario {

   const DOMINGO = "Domingo";

   const SEGUNDA_FEIRA = "Segunda-Feira";

   const TERCA_FEIRA = "Terça-Feira";

   const QUARTA_FEIRA = "Quarta-Feira";

   const QUINTA_FEIRA = "Quinta-Feira";

   const SEXTA_FEIRA = "Sexta-Feira";

   const SABADO = "Sábado";

   const NOME = "Classe DiasDaSemana";

   const TOTAL_DE_DIAS = 7;

  static $instancias = 0;

  private function __construct() {

     self::$instancias++;

   }

   public static function geraInstancia() {

    new self();

   }

   public static function imprimeConstantesNome() {

     return "A ".self::NOME." estende da ".parent::NOME;

   }

}

for ($i = 0; $i < 10; $i++) {

  DiasDaSemana::geraInstancia();

}

echo "Total de objetos da classe DiasDaSemanda criados:   

  ".DiasDaSemana::$instancias."\n";

echo "Hoje é ".DiasDaSemana::DOMINGO."\n";

echo "A semana tem um total de dias no valor de " . 

  DiasDaSemana::TOTAL_DE_DIAS."\n";

echo DiasDaSemana::imprimeConstantesNome();

?>

 

Figura 3. Resultado do código da Listagem 8

 

No exemplo da Listagem 9, criamos primeiramente uma classe Calendario e definimos uma constante dentro dela. Já na classe DiasDaSemana especificamos que esta devia estender de Calendario, além de criar várias constantes para armazenar o nome dos dias da semana e total de dias. Usamos um atributo estático nesta classe para guardar a quantidade de objetos criados. Também definimos o construtor como privado. Isso é usado para simular o padrão de projeto Singleton, e fizemos a criação de vários objetos via o método geraInstancia. Com isso exemplificamos mais algumas funcionalidades de orientação a objetos disponíveis no PHP.

 

Nota do DevMan

Os padrões de projeto, ou Design Patterns, são soluções para problemas recorrentes que surgem durante o desenvolvimento de um projeto. O padrão citado, Singleton, define uma solução para situações onde se deseja garantir que apenas uma instância de um determinado objeto exista durante toda a execução da aplicação, além de especificar um único local de acesso a esse objeto.

 

Vamos comentar um pouco sobre algumas particularidades ao se trabalhar com objetos no PHP. Um ponto que deve ser explicado refere-se à questão de quanto tempo um objeto PHP dura em memória. O tempo de vida desse objeto dura enquanto durar a execução do script PHP, já que não temos uma memória no estilo de ambientes de desenvolvimento como o desktop. Para que seja possível aproveitar um objeto já criado, devemos armazená-lo, por exemplo, em uma sessão. Porém também devemos tomar cuidado ao recuperar este objeto da sessão, já que a declaração da sua classe deve constar no ponto onde este é recuperado. Caso essa declaração não esteja presente, o objeto recuperado será do tipo stdClass do PHP, não tendo assim nenhuma das suas funcionalidades especificadas na classe original disponível. Para fazer essa declaração basta incluir a chamada do arquivo que contêm a definição da classe via funções include_once ou require_once, por exemplo. A função require_once foi utiliza no exemplo da Listagem 2.

 

Novidades para a versão 5.3

Após essa visão geral sobre objetos vamos falar um pouco sobre o futuro. O PHP 6 ainda vai demorar um pouco para ser lançado, contudo conforme o que se comenta nas listas da comunidade essa versão deve sair durante o ano de 2009. A boa notícia é que a versão 5.3 que esta para sair no último trimestre de 2008, contém inúmeras novidades esperadas pelos desenvolvedores há muito tempo. Dentre elas existem duas referentes a objetos. A questão de Namespaces e Garbage Collector para o gerenciamento de memória. Vamos a elas:

 

·         Namespaces: Essa era uma das funcionalidades mais pedidas e também uma das que causava mais controvérsias. Originalmente prevista para sair no PHP6, foi adiantada para a versão 5.3. Assim, essa versão contará com a implementação completa de namespaces, com suporte a autoload e namespaces hierárquicos. Isso permite aos desenvolvedores organizar melhor o código, evitando conflitos com bibliotecas internas do PHP ou de terceiros, criação de nomes de classes mais simples e principalmente produzindo um código mais limpo e legível. Essa funcionalidade ajudará muito o desenvolvimento de frameworks.

 

Em suma, com a introdução de namespaces no PHP você poderá fazer um código como mostrado a seguir:

 

namespace semana;

class Dia{

   const INICIO_SEMANA = 'Domingo';

   public function executar(){

     echo self::INICIO_SEMANA; 

   }

}

 

E seu uso poderá ser feito como segue. Veja que fazemos referência ao namespace semana diretamente na chamada da função executar(). Obviamente, o namespace semana poderá estar declarado no mesmo script PHP onde é chamado ou ainda em outro arquivo, requerendo claro sua inclusão no script usando include(), include_once(), require() ou require_once().

 

$objeto = semana::Dia::executar();

 

Há ainda a possibilidade de se usar o namespace semana usando a palavra reservada use, semelhante ao Delphi. Veja:

 

use semana;

$var = new Dia::executar();

 

·         Garbage Collector: Agora é possível fazer limpeza da memória que não é mais utilizada de uma forma mais direta, reduzindo os problemas como o fatídico Memory allocation error. As funções gc_enable e gc_disable vieram com essa finalidade.

 

Listamos duas das novidades referentes a objetos, porém esta versão contará com muitas outras como a melhora de performance em torno de 15%, uma nova biblioteca para conexão com MySQL entre outras novidades.

Para mais informações visite wiki.php.net/todo/php53, ali está listado o planejamento da versão e o que já foi feito para esse lançamento. Estas funcionalidades, que serão disponibilizadas, mostram que o PHP está em constante evolução, sempre atento às necessidades da comunidade e do mercado.

 

Conclusão

Durante o artigo focamos em apresentar alguns dos conceitos sobre orientação a objetos existentes no PHP. Existe muito mais além do que foi descrito no artigo como clonagem de objetos, reflexão, métodos mágicos, padrões de projetos entre outros assuntos interessantes. E de forma alguma como já dito no início gostaríamos de esgotar o assunto. O estudo não termina por aqui, uma visita ao site da linguagem vale a pena, visite www.php.net.

O manual on-line constante no site descreve vários exemplos e é uma ótima fonte de consulta para saber o que é possível fazer com objetos e PHP. Adicione também a leitura de livros, revistas, fóruns na internet que só tem a acrescentar ao processo de aprendizagem. O artigo também mostrou que o PHP está evoluindo sempre tentando agregar em seu núcleo boas práticas já implementadas em outras plataformas.

Finalizando pode-se dizer que OO é uma ótima prática para construção de sistemas. E que independente da linguagem uma vez aprendido o seu conceito, o desenvolvedor tem material para trabalhar com qualquer tecnologia, bastando, entretanto aprender a gramática de cada ferramenta. Espero ter contribuído no seu processo de conhecimento para entender OO + PHP.

Ao leitor saudações, bons estudos e até a próxima!

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?