Aprenda POO PHP

  • Página Inicial
  • Contato!
  • Tudo sobre POO PHP Parte 1!
  • Tudo sobre POO PHP Parte 2!
  • Tudo sobre POO PHP Parte 3!
  • Tudo sobre POO PHP Parte 4!
  • Tudo sobre POO PHP Parte 5!
  • Tudo sobre POO PHP Parte 6!
  • Tudo sobre POO PHP Parte 7!
  • Tudo sobre POO PHP Parte 2

    Exemplo Prático em PHP

    Vamos supor uma classe (primeira classe) com o nome ContaBanco, que pode ser criada por várias pessoas (portando, teria várias contas), com funções básicas como sacar, abrir e fechar contas, pagar mensalidades, etc. Ela teria um formato parecido com esses atributos e métodos:

    ContaBanco
    + numConta
    # tipo
    - dono
    - saldo
    - status
    + abrirConta(t)
    + fecharConta()
    + depositar(v)
    + sacar(v)
    + pagarMensal()

    Crie um arquivo de classe PHP com o nome ContaBanco.php, e coloque esse código:

    
    class ContaBanco {
        public $numConta;
        protected $tipo;
        private $dono;
        private $saldo;
        private $status;
        
        public function abrirConta($t) {
            $this->setTipo($t);
            $this->setStatus(true);
            if($t == "CC") {
                $this->setSaldo(50);
            }
            else if($t == "CP") {
                $this->setSaldo(150);
            }
            echo "<p>Conta aberta com sucesso!</p>";
        }
        public function fecharConta() {
            if($this->getSaldo() > 0) {
                echo "<p>A conta ainda tem dinheiro, não podemos fechá-la!</p>";
            }
            else if($this->getSaldo() < 0) {
                echo "<p>A conta está em débito, não podemos fechá-la!</p>";
            }
            else {
                $this->setStatus(false);
                echo "<p>A conta de {$this->getDono()} foi encerrada com sucesso!</p>";
            }
        }
        public function depositar($v) {
            if($this->getStatus()) {
                $this->setSaldo($this->getSaldo() + $v);
                // $this->saldo = $this->saldo + $v;
                echo "<p>Depósito de R\${$v} autorizado na conta de {$this->getDono()}.</p>";
                // O \$ é pra não conflitar com o $ da variável.
            }
            else {
                echo "<p>Conta Fechada ou Inexistente!</p>";
            }
        }
        public function sacar($v) {
            if($this->getStatus()) {
                if($this->getSaldo() >= $v) {
                    $this->setSaldo($this->getSaldo() - $v);
                    // $this->saldo = $this->saldo - $v;
                    echo "<p>Saque de R\${$v} autorizado na conta de {$this->getDono()}.</p>";
                }
                else {
                    echo "<p>Saldo insuficiente para saque!</p>";
                }
            }
            else {
                echo "<p>Essa conta tá fechada ou não existe!</p>";
            }
        }
        public function pagarMensal() {
            if($this->getTipo() == "CC") {
                $v = 12;
            }
            else if($this->getTipo() == "CP") {
                $v = 20;
            }
            
            // Outra condição
            
            if($this->getStatus()) {
                $this->setSaldo($this->getSaldo() - $v);
                echo "<p>Mensalidade de R\${$v} debitada da conta de {$this->getDono()}.</p>";
            }
            else {
                echo "<p>Problemas na conta, não podemos cobrar.</p>";
            }
        }
        
        // Especiais:
        
        public function __construct() {
            $this->setSaldo(0);
            $this->setStatus(false);
            echo "<p>Conta criada com sucesso.</p>"; // Apague depois. Não é recomendado colocar echo aqui, é só pra testar.
        }
        
        public function __destruct() {
            echo "Objeto ContaBanco Destruído!<br/>";
        }
        
        public function getNumConta() {
            return $this->numConta;
        }
    
        public function getTipo() {
            return $this->tipo;
        }
    
        public function getDono() {
            return $this->dono;
        }
    
        public function getSaldo() {
            return $this->saldo;
        }
    
        public function getStatus() {
            return $this->status;
        }
        
        public function setNumConta($numConta) {
            $this->numConta = $numConta;
        }
    
        public function setTipo($tipo) {
            $this->tipo = $tipo;
        }
    
        public function setDono($dono) {
            $this->dono = $dono;
        }
    
        public function setSaldo($saldo) {
            $this->saldo = $saldo;
        }
    
        public function setStatus($status) {
            $this->status = $status;
        }
    }
    
    

    PS: Prefira usar métodos setter do que mexer direto nos atributos.

    Com esse código pronto, vá no index e coloque esses comandos pra criar os objetos:

    
    require_once "ContaBanco.php";
    
    $p1 = new ContaBanco();
    $p2 = new ContaBanco();
    
    $p1->abrirConta("CC");
    $p1->setNumConta(1111);
    $p1->setDono("Jubileu");
    
    $p2->abrirConta("CP");
    $p2->setNumConta(2222);
    $p2->setDono("Creuza");
    
    print_r($p1);
    print_r($p2);
    
    unset($p1);
    unset($p2);
    
    

    Para depositar, basta colocar isso, no final do código, antes do print_r():

    
    $p1->depositar(300);
    $p2->depositar(500);
    
    

    Para sacar, da mesma forma:

    
    $p2->sacar(100);
    
    

    E cobrar mensalidade também:

    
    $p1->pagarMensal();
    $p2->pagarMensal();
    
    

    Tente outros números, principalmente na parte de sacar. E tente as outras funções.

    Paralelamente, podemos fazer um exemplo apenas com métodos e atributos estáticos:

    
    class Ventilador {
        private static $ligado = false;
        private static $velocidade = 0;
        
        public static function ligar($vel) {
            self::$ligado = true;
    
            if($vel < 1) {
                $vel = 1;
            }
            else if($vel > 3) {
                $vel = 3;
            }
    
            self::$velocidade = $vel;
            
            printf("O ventilador está ligado, na velocidade de %d.<br/>", self::$velocidade);
        }
    
        public static function desligar() {
            self::$velocidade = 0;
            self::$ligado = false;
    
            echo "O ventilador está desligado!<br/>";
        }
    
        public static function getLigado() {
            return self::$ligado;
        }
    
        public static function getVelocidade() {
            return self::$velocidade;
        }
    
        public static function setLigado($ligado) {
            self::$ligado = $ligado;
        }
    
        public static function setVelocidade($velocidade) {
            self::$velocidade = $velocidade;
        }
    }
    
    

    E no programa principal:

    
    require_once "Ventilador.php";
    
    Ventilador::ligar(3);
    Ventilador::ligar(2);
    Ventilador::desligar();
    
    echo (Ventilador::getLigado() ? "true" : "false") . "<br/>";
    
    

    Encapsulamento

    Como sabemos, a POO tem três pilares, Encapsulamento, Herança e Polimorfismo (representados pelas letras EHP). O primeiro que vamos tratar é o encapsulamento.

    PS: Alguns consideram a Abstração um dos pilares também, o primeiro deles, mas na verdade ele está dentro do encapsulamento.

    Imagine que o carro, uma pilha ou qualquer outra coisa esteja numa "cápsula", no exemplo, vamos usar um controle remoto. O código estando encapsulado, ele está protegido internamente (como uma cápsula de remédio mesmo), deixando o que é pra ser privado "blindado" do usuário, e o que é público com contato permitido.

    A pilha também é um ótimo exemplo de encapsulamento, onde os componentes químicos que geram a eletricidade estão protegidos do contato humano (para proteger tanto os componentes quanto a pessoa), mas as partes metálicas estão disponíveis para fornecer energia ao produto. Além disso, a pilha sempre tem um formato padrão (tipo o AAA) para servir em vários produtos, independente da funcionalidade do produto. Mesmo se o componente interno da pilha for diferente (alcalina, comum, recarregável, etc.).

    No exemplo que usaremos, o controle remoto, a "cápsula" seria a capa que permite que nós interaja com ele, e o código seria os circuitos que operam isso, mas que não podemos tocar diretamente por segurança.

    O código "encapsulado" tem o mesmo padrão, e protege o código do usuário e vice-versa, impedindo que o programador cometa erros e prejudique o programa como um todo, independente do código encapsulado (ele só verificará as informações necessárias, sem precisar saber como ele funciona exatamente).

    Em outras palavras, encapsular é ocultar partes independentes da implementação, permitindo construir partes invisíveis ao mundo exterior.

    Basicamente, o uso de atributos privados e o acesso a eles ser feito através de métodos (como os getters e setters), já é o encapsulamento. Mas podemos fazer isso a nível de classe, usando uma interface, que obrigará a classe a ter todos os métodos descritos nela, além de proteger os atributos da classe implementadora do programa principal.

    Para criar um exemplo disso com um controle remoto, temos que definir uma interface (seria a "cápsula" do controle com os botões), de forma parecida com uma classe, mas sem atributos, e todos os métodos são públicos. E a classe ControleRemoto (como os circuitos encapsulados pela interface) terá os atributos e os métodos getters e setters privados (é o passo principal pra encapsular). Veja o que faremos no PHP:

    <<interface>>
    Controlador
    + ligar()
    + desligar()
    + abrirMenu()
    + fecharMenu()
    + maisVolume()
    + menosVolume()
    + ligarMudo()
    + desligarMudo()
    + play()
    + pause()
    ControleRemoto
    - volume
    - ligado
    - tocando
    (Receberá elementos do controlador)
    - setVolume(volume)
    - getVolume()
    - setLigado(ligado)
    - getLigado()
    - setTocando(tocando)
    - getTocando()

    Crie uma nova Interface em PHP com o nome Controlador.php com esse código:

    
    interface Controlador {
        public function ligar();
        public function desligar();
        public function abrirMenu();
        public function fecharMenu();
        public function maisVolume();
        public function menosVolume();
        public function ligarMudo();
        public function desligarMudo();
        public function play();
        public function pause();
    }
    
    

    PS: Os métodos abstratos significam que o método não será desenvolvido na interface, e sim na classe. É como um aviso pra interface que existe um método (por exemplo, de abrir, aumentar volume, etc.), mas a interface não precisa e nem sabe como o código funciona na classe, apenas esta que tem que implementar (executar). Se um método a ser implementado numa classe for estático, ele não pode ser indicado na interface. Interfaces agem de forma parecida com uma classe abstrata, só que sem implementações e sem atributos, apenas a assinatura dos métodos, que são abstratos por padrão, dispensando a indicação de abstract neles.

    Crie também a classe ControleRemoto.php, assim (os atributos deverão estar privados, os métodos getter e setter não são obrigatórios ser):

    
    require_once "Controlador.php";
    
    class ControleRemoto implements Controlador {
        private $volume;
        private $ligado;
        private $tocando;
        
        // Métodos especiais.
        
        public function __construct() {
            $this->volume = 50;
            $this->ligado = false;
            $this->tocando = false;
        }
    
        public function ligar() {
            $this->setLigado(true);
        }
        
        public function desligar() {
            $this->setLigado(false);
        }
        
        public function abrirMenu() {
            echo "<br/>Está ligado? " . ($this->getLigado() ? "SIM" : "NÃO");
            echo "<br/>Está tocando? " . ($this->getTocando() ? "SIM" : "NÃO");
            echo "<br/>Volume: " . $this->getVolume();
            for($i = 0; $i < $this->getVolume(); $i += 2) {
                echo "|";
            }
            echo "<br/>";
        }
        
        public function fecharMenu() {
            echo "<br/>Fechando menu...";
            
        }
    
        public function maisVolume() {
            if($this->getLigado()) {
                if($this->getVolume() < 100) {
                    $this->setVolume($this->getVolume() + 2);
                }
            }
            else {
                echo "<br/>ERRO! Está desligado, não posso aumentar o volume!";
            }
        }
    
        public function menosVolume() {
            if($this->getLigado()) {
                if($this->getVolume() > 0) {
                    $this->setVolume($this->getVolume() - 2);
                }
            }
            else {
                echo "<br/>ERRO! Está desligado, não posso diminuir o volume!";
            }
        }
        
        public function ligarMudo() {
            if($this->getLigado() && $this->getVolume() > 0) {
                $this->setVolume(0);
            }
        }
        
        public function desligarMudo() {
            if($this->getLigado() && $this->getVolume() == 0) {
                $this->setVolume(50);
            }
        }
    
        public function play() {
            if($this->getLigado() && !($this->getTocando())) {
                $this->setTocando(true);
            }
        }
        
        public function pause() {
            if($this->getLigado() && $this->getTocando()) {
                $this->setTocando(false);
            }
        }
        
        private function setVolume($volume) {
            $this->volume = $volume;
        }
        
        private function getVolume() {
            return $this->volume;
        }
    
        private function setLigado($ligado) {
            $this->ligado = $ligado;
        }
    
        private function getLigado() {
            return $this->ligado;
        }
        
        private function setTocando($tocando) {
            $this->tocando = $tocando;
        }
        
        private function getTocando() {
            return $this->tocando;
        }
    }
    
    

    PS: Usamos implements quando precisamos implementar uma interface, sendo obrigado executar todos os métodos descritos nela, é possível uma classe implementar mais de uma interface, com os nomes separados por vírgulas, usando algo como class NomeDaClasse implements NomeDaInterface1, NomeDaInterface2.

    E para criar o controle, fazemos assim no index:

    
    require_once "ControleRemoto.php";
    
    $c = new ControleRemoto();
    $c->ligar();
    $c->maisVolume(); // Aqui podemos colocar os outros métodos.
    $c->abrirMenu();
    
    

    Como exemplo, crie outros exemplos e funções baseados nesse controle.

    Essa é a vantagem do encapsulamento, ele protege o código contra ações externas e internas, e torna a forma interna de implementação invisível pro "lado de fora" (sabemos que quem mexe nela sabe como usar as funções, mas não como funcionam, até os métodos getter e setter são privados por isso).

    Em outras palavras, as interfaces estabelecem contratos entre as classes que as implementam, garantindo que elas tenham um certo comportamento.

    As interfaces também garantem o encapsulamento, já que podemos usar somente os métodos descritos na interface nos objetos, e não permitir a visualização de atributos da classe implementadora. Só que isso faz mais diferença em linguagens fortemente tipadas, como o Java, o que não é o caso do PHP.