segunda-feira, 26 de março de 2012

Curso de PHP Orientado a Objetos - Parte 6

Vamos começar a semana com o sexto artigo do Curso de PHP Orientado a Objetos.

Para conhecer as demais partes, clique aqui.

Ao final deste artigo, você será capaz de:
  • Entender o significado do encapsulamento para a POO;
  • Entender e aplicar a visibilidade dos métodos e propriedades.

Encapsulamento

É um dos recursos mais interessantes que a programação orientada a objetos nos fornece. Trata-se de um mecanismo que provê proteção de acesso aos membros internos de um objeto.
Alguns métodos e propriedades devem ser só de responsabilidade da classe-pai. Sem os modificadores de acesso, ela perde esta responsabilidade, fazendo com que outras classes tenham acesso a estes métodos e propriedades.
Para atingir o encapsulamento, uma das formas é definindo a visibilidade das propriedades e dos métodos de um objeto. A visibilidade define a forma como essas propriedades devem ser acessadas. Existem três formas de acesso:
  1. private: Este modificador não permite ser acessado por classes descendentes (classes-filhas), só pode ser acessado dentro da própria classe.
  2. public: Este modificador é o default (padrão), ou seja, quando um método não tiver um modificador de visibilidade definido, ele sempre será public. Public significa que o método ou propriedade em questão pode ser acessado por todas as outras classes e métodos sem quaisquer restrições.
  3. protected: Pode ser acessado apenas por métodos da própria classe e classes filhas.
Podemos dizer que o encapsulamento nos permite "ocultar" tudo aquilo que não é "importante", ou seja, detalhes internos do funcionamento da classe são ocultos para os objetos. O objeto só conhece o que é necessário, o que ele não precisa saber/conhecer, fica oculto (a nível de objeto).


Private

Até agora, nos artigos anteriores, declaramos classes como public e não definimos visibilidades dos métodos. Vamos iniciar com um exemplo prático, para facilitar a compreensão.
A proposta é criar uma classe chamada Fornecedor e marcaremos algumas das propriedades como private. Dessa forma, os elementos private só poderão ser alterados por métodos da mesma classe. Deixaremos para livre acesso, o nome e o valor, marcado como public.
class Fornecedor{
   private $Id;      //identificação
   public  $Nome;    //nome do produto
   private $Compra;  //valor de compra
   public  $Valor;   //valor de venda

}
Observe a imagem abaixo:


Eclipse exibindo apenas as propriedades públicas da classe Fornecedor
Eclipse exibindo apenas as propriedades públicas da classe Fornecedor
Criamos o objeto Fornecedor e ao definir as propriedades, o próprio Eclipse, através de sua função autocomplete, carregará somente as funções públicas (public). Perceba que ele não exibe na lista as funções privadas (private).


Se mesmo assim você tentar algo como:
$empresa1 = new Fornecedor();
$empresa1->Compra = 400;
Será retornado uma mensagem de erro, pois a propriedade Compra é privada (private).


Ok, mas como faço para atribuir algo a essa propriedade caso necessário?
Se você fez essa pergunta, parabéns!
Para atribuir algo, basta criar um método pertencente a classe Fornecedor que manipule estas propriedades. Que tal chamarmos de "Set" para definir e "Get" para obter o conteúdo dos atributos?
Veja o exemplo:
class Fornecedor{
   private $Id;      //identificação
   public  $Nome;    //nome do produto
   private $Compra;  //valor de compra
   public  $Valor;   //valor de venda

/* Olha o método setCompra()
 * que vai definir um valor para
 * a propriedade $Compra
*/
 public function setCompra($Compra){

 if (is_numeric($Compra) && $compra > 0)
 {
    $this->Compra = $Compra;
 }

 }
/* Vamos agora criar o método
 * getCompra que vai retornar
 * o conteúdo da propriedade $compra
*/
 public function getCompra(){

  return $this->Compra;

 }
}


Agora que criamos o método get e set para a propriedade $Compra, é possível realizar a chamada normalmente:
$empresa1 = new Fornecedor();
$empresa1->Nome = "Vale";
$empresa1->setCompra(400);
echo "O valor do produto ".$empresa1->Nome." é de ".$empresa1->getCompra();


O interessante neste caso, é perceber que para um determinado valor chegar a propriedade $Compra, ele deve passar pelo método setCompra. Isso nos traz um controle maior sobre a aplicação visto que, você pode realizar várias operações antes da chagada do valor, neste caso perceba que no método setCompra, checamos se o valor é um número (is_numeric) e se é maior que zero.
Poderíamos criar um set e um get para mais elementos definidos como private mas cuidado, utilize os Getters e Setters somente quando existe a real necessidade, variáveis internas ou que não precisam de nenhum tipo de verificação ou tratamento, não utilize.
Prefira sempre utilizar métodos Getter e Setters ao invés de um campo público (public) mas lembre-se, simplificar é a alma da POO, criar dezenas de métodos não simplifica.


Protected


Vimos no exemplo anterior, o uso do parâmetro de visibilidade private. Vale ressaltar que quando uma propriedade é definida como private, ela não pode ser sobrescrita por classes filhas, ou seja, uma classe filha não consegue chamar os métodos setters e getters da classe pai (no caso do atributo estar como private).
Caso você tenha uma classe Funcionário com o método setSalario e o atributo Salário do tipo private, e crie a subclasse Estagiário, você não consegue chamar o método mesmo fazendo uso da herança, está é uma característica do private.
Em outras palavras, se um atributo é do tipo private, ele só funciona na classe que foi declarado, caso você queira fazer uso do mesmo em outras classes (filhas) é necessário modificar o tipo para Protected.


Veja:
class Funcionario{
  private $Id;
  private $Nome;
  private $Nascimento;
  private $Salario;

 function setSalario($Salario){

   if (is_numeric($Salario) && $Salario > 0)
   {
      $this->Salario = $Salario;
   }

 }

 function getSalario(){

   return $this->Salario;

 }

}

Agora, vamos criar a classe Estagiário, que será uma subclasse de Funcionário.
class Estagiario extends Funcionario {
  /* Método getSalario será
   * sobrescrito pois o estagiário
   * neste modelo possui um bônus
   * de 10%
   */ 

  function getSalario(){
   return $this->Salario * 1.10;
  }

}
Depois das duas classes criadas, vamos criar o objeto estagiário:
$junior = new Estagiario;
$junior->setSalario(300);
echo "O salario é: ".$junior->getSalario;


Essa ação resultaria em um erro. Isso ocorre porque a propriedade $Salario é uma propriedade private, o que significa que ela somente pode ser acessada de dentro da classe em que ela foi declarada, neste caso, a classe Funcionário.
Para que as subclasses consigam acessar uma propriedade da classe pai, definimos como protected.


Exemplo:
class Funcionario{
  private   $Id;
  private   $Nome;
  private   $Nascimento;
  protected $Salario;

 function setSalario($Salario){

   if (is_numeric($Salario) && $Salario > 0)
   {
      $this->Salario = $Salario;
   }

 }

 function getSalario(){

   return $this->Salario;

 }

}

Agora podemos criar a classe Estagiário da mesma forma que fizemos no exemplo anterior e em seguida criar o objeto:
$junior = new Estagiario;
$junior->setSalario(300);
echo "O salario é: ".$junior->getSalario;


Com essa pequena modificação, tornamos o atributo $Salario "extensível" a todas as classes que forem criadas a partir da classe Funcionário. Este exemplo não retornaria erro.

Public


Explicar o comportamento do modificador de acesso public é simples, pois é a propriedade padrão do PHP. Basicamente, quando não é definido a visibilidade, ela será pública ou seja, você pode modificar, herdar ou atribuir sem nenhum impedimento, não é necessário os métodos Getters e Setters para propriedades públicas.


Terminamos aqui mais um artigo.
No próximo veremos constantes e propriedades estáticas.


Utilize o espaço de comentários para dúvidas, sugestões e elogios.
Ps.: Venho recebendo alguns comentários que tem servido de estímulo para a continuação desta série. Muito obrigado!


Nenhum comentário:

Postar um comentário