-
Notifications
You must be signed in to change notification settings - Fork 1
2.4.2 Orientação a Objetos
A orientação a objetos (OO) é um padrão de programação em que um software não é composto por um grande bloco de códigos específicos, e sim de vários blocos de códigos distantes e independentes, que juntos montam um sistema. O PHP faz parte de um grupo de linguagens que possuem suporte a OO, mas não é preso a ela. Esse padrão não possui um objetivo único e tem como objetivo:
- Reutilização de código (tempo economizado);
- Escalabilidade (código adicionado mais facilmente);
- Manutenibilidade (manutenção mais fácil);
- Desenvolvimento mais rápido.
A POO possui alguns conceitos fundamentais para seu desenvolvimento:
- Abstração: É a capacidade que temos em abstrair o mundo real em objetos. Ou seja, criarmos representações (por meio de objetos) do mundo real. Da mesma forma como ocorre no mundo real, teremos objetos com identidade (nome), características e que executem ações afim de prover o funcionamento do sistema como um todo.
- Objetos: um objeto é uma entidade do mundo real, concreta ou abstrata, que seja aplicável ao sistema;
- Classes: uma classe é a representação de vários objetos que possuem as mesmas características e comportamentos;
- Atributos / Propriedades: são as características de um determinado objeto.
Algo que confunde bastante novos estudantes de Orientação a Objetos é a diferença entre Classes e Objetos. As classes definem as características e o comportamento dos seus objetos. Cada característica é representada por um atributo e cada comportamento é definido por um método, logo uma classe não é um objeto e sim uma abstração de sua estrutura, no qual podemos definir quantos objetos desejamos ter. Para podermos entender melhor o funcionamento, vamos criar a nossa primeira classe e alguns objetos a partir dela, conforme o exemplo a seguir:
<?php
Class Conta {
}
$conta = new Conta();
$conta2 = new Conta();
$conta3 = new Conta();
?>
Criamos uma classe vazia de uma conta junto com três objetos que são dessa conta criada. Podemos dizer então que os três objetos são do tipo conta. E é dessa maneira que funciona todo objeto, seu tipo será sempre a classe a partir do qual ele é criado.
Uma classe é composta por atributos e métodos, que juntos dão funcionalidade a um objeto. Podemos ver no próximo exemplo, uma classe composta por dois atributos e três métodos.
<?php
Class Conta {
public $saldo = 500;
public $titular;
function sacar($valor) {
}
function depositar($valor) {
}
function verSaldo() {
}
}
$conta1 = new Conta();
$conta1->depositar(500);
$conta1->sacar(20);
$conta2 = new Conta();
$conta2->depositar(250);
$conta2->verSaldo();
?>
A classe Conta tem como atributos o saldo da conta e o titular. E como métodos possui depositar(), sacar() e verSaldo(). Para acessarmos o método depositar() do nosso objeto $conta1 precisamos utilizar uma seta(->). Seu nome é Operador de Acesso a Objetos e é através dessa seta que indicamos que estamos acessando um atributo ou método de tal objeto. Faremos agora uma codificação mais completa em cima de nossa classe Conta, como podemos observar no exemplo a segur:
<?php
Class Conta {
public $saldo = 0;
public $titular;
function depositar($valor) {
$this->depositar += $valor;
}
function sacar($valor) {
if(($this->saldo > 0) && ($this->saldo >= $valor)) {
$this->saldo -= $valor;
}
else {
echo "Saldo insuficiente";
}
}
function verSaldo() {
echo "Saldo Atual:".$this->saldo. "<br>";
}
}
$novaConta = new Conta();
$novaConta->verSaldo();
$novaConta->depositar(500);
$novaConta->verSaldo();
$novaConta->sacar(150);
$novaConta->verSaldo();
?>
Note que para acessarmos nossos atributos dentro dos métodos utilizamos a variável reservada $this. Se fosse preciso chamar algum método da própria classe dentro de um outro método teríamos de usar $this, que é usado para acessar atributos e métodos da própria classe e só existe dentro deste escopo. No PHP ele é fundamental e obrigatório, já em algumas outras linguagens de programação $this é opcional.
Um dos conceitos fundamentais da OO é a herança de classes, pois permite que uma classe estenda outra e a classe filha vai herdar todos os atributos e métodos da classe pai. Ela pode então tanto possuir novos métodos e atributos, quanto reescrever métodos já existentes, como mostra o próximo exemplo:
<?php
class Conta {
public $saldo = 0;
function depositar($valor) {
}
function sacar() {
}
}
class ContaCorrente extends Conta {
function transferir($contaDestino, $valor) {
$this->saldo -= $valor;
}
}
$novaConta = new ContaCorrente();
$novaConta->transferir('xxx-xxx', 500);
echo "Saldo:".$novaConta->saldo;
?>
Uma classe abstrata é uma classe que não pode ser instanciada como um objeto diretamente. Ela tem que ser estendida por alguma classe concreta, e quando um objeto desta classe for criado, ele herdará métodos e atributos da classe abstrata. Veja o próximo exemplo:
<?php
abstract class ClasseAbstrata {
// Esse método abstrato apenas define os argumentos requeridos
abstract protected function prefixName($name);
}
class ClasseConcreta extends ClasseAbstrata {
// O método filho pode definir argumentos opcionais não presentes na assitura abstrata
public function prefixName($name, $separator = ".") {
if ($name == "Pacman") {
$prefix = "Mr";
} elseif ($name == "Pacwoman") {
$prefix = "Mrs";
} else {
$prefix = "";
}
return "{$prefix}{$separator} {$name}";
}
}
$class = new ClasseConcreta;
echo $class->prefixName("Pacman"), "\n";
echo $class->prefixName("Pacwoman"), "\n";
?>
Note que a classe estendida faz uso dos métodos declarados na classe abstrata, ou seja, em classes abstratas e concretas o conceito de herança é o mesmo. Mas, para que serve uma classe abstrata? Vamos pensar no funcionamento de um banco, onde os clientes podem ter uma conta corrente e poupança: o funcionamento de uma conta segue um determinado padrão, o que difere uma da outra são as ações (métodos) que podemos executar.
Podemos ter também métodos abstratos em nossas classes, como mostra o próximo exemplo:
<?php
abstract class Conta {
public $saldo = 0;
public function sacar() {
}
public function depositar($valor) {
}
}
class ContaPoupanca extends Conta {
public function resgatar($valor) {
}
}
$conta1 = new ContaPoupanca();
$conta1->depositar(500);
$conta1->resgatar(250); ?>
?>
Todo método abstrato precisa, obrigatoriamente, ser implementado na classe filha, ou seja, todas as contas, independentemente do tipo devem possuir as operações básicas de saque, depósito, transferência e consulta. Porém, contas de tipos diferentes podem tratar estas ações de formas diferentes. Por exemplo: um depósito em uma conta poupança gera um certo rendimento ao saldo aplicado - para este caso um método abstrato é uma forma de garantir que este método seja implementado na classe ContaPoupança e em todas as outras classes que estendê–las.
Uma classe final é uma classe que não pode ser estendida por nenhuma outra classe, ou seja, a classe final não tem herdeiros, pois ela é a última de sua hierarquia. Em nosso exemplo temos uma conta do tipo poupança que, pela regra de negócio de um banco, não possui uma derivação, ou seja, não deve ser estendida. Para estes casos definimos a classe como final, ou seja, somente existirão objetos da classe poupança e não filhos da mesma, pois o correto é que todas as contas estendam a nossa classe pai Conta e mais nenhuma outra, como mostra o próximo exemplo:
<?php
final class ContaPoupanca {
public function resgatar($valor) {
}
public function verSaldo() {
}
}
$poupanca = new ContaPoupanca();
$poupanca->resgatar(250);
?>
Também podemos ter métodos finais que jamais podem ser reescritos nas classes filhas. Em nosso exemplo de agência bancária, podemos concluir que o método sacar de uma Conta é padrão para todas as Contas, independentemente de seu tipo. Quando temos uma situação como esta podemos definir estes métodos como final, impedindo assim que eles sejam reescritos e saiam do padrão estabelecido na classe pai, como mostra o exemplo a seguir:
<?php
class Conta {
public function depositar($valor) {
}
final public function sacar($valor) { #método final, não pode ser reescrito
}
}
class ContaCorrente extends Conta{ public function depositar() {
public function depositar() {
}
}
?>
Traits, a partir do PHP 5.4, nos proporcionam uma maneira simples e objetiva de reaproveitamento de código, pois são como classes onde usamos a palavra reservada trait, então escrevemos os métodos que queremos. E para usarmos um trait em uma classe usamos a palavra USE, como podemos observar no próximop exemplo:
<?php
class Conta {
public $saldo = 0;
public function getSaldo() {
echo "Saldo Atual: {$this->saldo}";
}
}
trait Acoes {
public function getSaldo(){
echo "Saldo Disponivel: {$this->saldo}";
}
public function depositar($valor){
$this->saldo += $valor;
}
public function sacar($valor){
if($this->saldo >= $valor) {
$this->saldo -= $valor;
}
}
}
class ContaCorrente extends Conta {
use Acoes;
}
$o = new ContaCorrente();
$o->depositar(500);
$o->sacar(200);
$o->getSaldo();
// Saldo Disponivel: 300
?>
Note que o método getSaldo() foi reescrito dentro do Trait, ou seja, irá sobrescrever os métodos da classe base (pai). Podemos ainda usar múltiplos traits em nossas classes, como no próximo exemplo.
<?php
class Conta {
public $saldo = 0;
public function getSaldo() {
echo "Saldo Atual: {$this->saldo}";
}
}
trait Acoes {
public function depositar($valor) {
$this->saldo += $valor;
}
public function sacar($valor) {
if($this->saldo >= $valor) {
$this->saldo -= $valor;
}
}
}
trait consultaExtrato {
public function getSaldo() {
echo "Saldo Disponivel para saque:{$this->saldo}<br>";
}
public function gerarExtrato($periodo) {
echo "Gerando extrato período $periodo aguarde...";
}
}
class ContaCorrente extends Conta {
use Acoes, consultaExtrato;
}
$o = new ContaCorrente();
$o->depositar(500);
$o->sacar(200);
$o->getSaldo();
$o->gerarExtrato('20/01/2013');
?>
Desta vez temos dois traits com nomes diferentes, e note que sobrescrevemos o método getSaldo() novamente no trait consultaExtrato.