1-PHP Introdução
Exercícios
Curso Banco Dados
IntroducaoBD.php

Cap. 3 - PHP Orientado a Objetos

3.1 - Introdução a POO com PHP

Objetivo: Estudar a Programação orientada a objetos no PHP.

Conteúdo:




Introdução

(voltar início)

Programação Orientada a Objetos, POO, é um paradigma de programação que se baseia em modelos semelhantes a vida real. Faz uso de objetos, que possuem propriedades (ou atributos) e que agem com ou em outro objeto.

Algumas observações importantes:
  • O POO do PHP4 é diferente do PHP5
  • A partir do PHP 5, o modelo de objetos foi rescrito para permitir melhor performance e mais funcionalidades.
  • Esta é uma grande modificação do PHP 4. PHP 5 tem um modelo de objetos completo.
  • Entre outras novidades do PHP 5 estão a inclusão de visibility, classes e metodos abstract e final.
Nas seções seguintes veremos algumas características da POO do PHP.

Lembre-se que o PHP5 não é uma linguagem de programação orientada a objetos. Na verdade o PHP possui recursos para que seus scripts sejam organizados segundo o paradigma da POO.

Veja dois documentos com explicações sobre POO no PHP:

Principais Conceitos da Programação Orientada a Objetos

(voltar início)

A seguir resumimos os principais conceitos da programação POO.

  • Classe (Class) - Este é um tipo de dados definido pelo programador, que inclui funções locais e dados locais. Clase é um modelo para se criar objetos. Podemos pensar em uma classe como um modelo para fazer muitas instâncias do mesmo tipo (ou classe) de objeto.

  • Objeto (Object) - Uma instância individual da estrutura de dados definida por uma classe. DEfinimos uma classe como sendo algo de abrangência geral e depois criamos objetos dessa classe (ou "instanciamos objetos"). Uma classe pode ter muitos ojetos. Os objetos também são conhecidos como instâncias.

  • Variável Membro (Member Variable) - são as variáveis ​​definidas dentro de uma classe. Esses dados ficarão invisíveis para o exterior da classe e podem ser acessados ​​por meio de "funções membro". Essas variáveis ​​são chamadas de atributo do objeto quando o objeto é criado a parti da classe.

  • Função Membro (Member Function) - são as funções definidas dentro de uma classe e são usadas para acessar os dados do objeto.

  • Herança (Inheritance) - quando uma classe é definida herdando uma função existente de uma classe pai, isso é chamado de herança. A classe filha herdará todas ou algumas funções-membro e variáveis ​​de uma classe pai.

  • Classe Pai (Parent Class) - uma classe que é herdada por outra classe. Isso também é chamado de classe base ou superclasse.

  • Classe Filha (Child Class) - uma classe que herda de outra classe. Isso também é chamado de subclasse ou classe derivada.

  • Polimorfismo (Polymorphism) - Este é um conceito orientado a objetos onde a mesma função pode ser usada para finalidades diferentes. Por exemplo, o nome da função permanecerá o mesmo, mas leva um número diferente de argumentos e pode realizar tarefas diferentes.

  • Sobrecarga (Overloading) - um tipo de polimorfismo no qual alguns ou todos os operadores têm implementações diferentes dependendo dos tipos de seus argumentos. Funções semelhantes também podem ser sobrecarregadas com implementações diferentes.

  • Sobreposição (Overrinding) - A Sobreposição de métodos (override) é um conceito do polimorfismo que nos permite reescrever um método, ou seja, podemos reescrever nas classes filhas métodos criados inicialmente na classe pai, os métodos que serão sobrepostos, diferentemente dos sobrecarregados, devem possuir o mesmo nome, tipo de retorno e quantidade de parâmetros do método inicial, porém o mesmo será implementado com especificações da classe atual, podendo adicionar um algo a mais ou não.

  • Abstração de dados (Data Abstraction) - qualquer representação de dados em que os detalhes de implementação são ocultados (abstraídos).

  • Encapsulamento (Encapsulation) - refere-se a um conceito em que encapsulamos todos os dados e funções-membro juntos para formar um objeto.

  • Construtor (Constructor) - refere-se a um tipo especial de função que será chamada automaticamente sempre que houver uma formação de objeto de uma classe.

  • Destrutor (Destructor) - refere-se a um tipo especial de função que será chamada automaticamente sempre que um objeto for excluído ou sair do escopo.

Definindo classes em PHP

A forma geral para definir uma nova classe em PHP é apresentada a seguir.

Estrutura Básica de uma Classe em PHP

                            
<?php
   class phpClass {
      var $var1;
      var $var2 = "constant string";
      
      function myfunc ($arg1, $arg2) {
         [..]
      }
      [..]
   }
   ?>
                            
                    

Nesse estrutura temos:

  • A palavra class é usada para definir a criação da classe e deve ser seguida pelo nome da classe.

  • Ela é aberta (e fechada) com chaves { } entre as quais são feitas as declarações da variáveis e funções.

  • As declarações de variáveis ​​começam com palavra chave var , que é seguida por um nome de variável, $variavel;. Podemos também definir variáveis com valores.

  • As definições de funçãosão feitas como as funções em PHP: iniciam-se com a palavra chave function. Elas são locais para a classe e serão usadas para definir e acessar dados do objeto.

O próximo exemplo define uma classe que trabalha com livros. É a classe Books

Exemplo 1: Classe Books

                            
<?php
class Books {
      /* Variáveis Membros */
      var $price;
      var $title;
      
      /* Funções Membro */
      function setPrice($par){
         $this->price = $par;
      }
      
      function getPrice(){
         echo $this->price ."
"; } function setTitle($par){ $this->title = $par; } function getTitle(){ echo $this->title ."
"; } } ?>
  • A variável $this é uma variável especial e é usada para se fazer referência ao próprio objeto. Ou seja ela "substitui o objeto quando é chamada".

  • O pperador de objeto, -> é usado para acessar um membro do objeto e obter seu valor. Equivale ao operador "ponto" em outras linguagens OO.

  • Criação de objetos em PHP

    Depois de criar a classe, podemos criar quantos objetos forem necessários. Para criar um novo objeto usamos o operador new.

    
    $physics = new Books;
    $maths = new Books;
    $chemistry = new Books;
    
    

    Acima, criamos três objetos e esses objetos são independentes um do outro. A seguir, veremos como acessar funções-membro e processar variáveis-membro.

    Chamando as Funções Membro

    Depois de criar os objetos podemos chamar as funções de membro relacionadas a ele. Uma função de membro será capaz de processar a variável-membro do objeto. O trecho a seguir mostra como definir o título e os preços dos três livros chamando as funções de membro.
    
    $physics->setTitle( "Physics for High School" );
    $chemistry->setTitle( "Advanced Chemistry" );
    $maths->setTitle( "Algebra" );
    
    $physics->setPrice( 10 );
    $chemistry->setPrice( 15 );
    $maths->setPrice( 7 );
    
    

    Podemos obter os valores, usando as funções getTitle e getPrice:

    
    $physics->getTitle();
    $chemistry->getTitle();
    $maths->getTitle();
    $physics->getPrice();
    $chemistry->getPrice();
    $maths->getPrice();
    
    

    As instruções acima resultam em:

    
    Physics for High School
    Advanced Chemistry
    Algebra
    10
    15
    7
    
    

    Construtores e Destrutores

    (voltar início)

    Usando Construtores

    Construtor (Função construtor) é um tipo especial de função que é chamada automaticamente sempre que um objeto é instanciado (criado).

    Ele permite que sejam inicializadas as propriedades de um objeto quand da sua criação.

    Se criarmos a função __construct (), o PHP irá chamá-la automaticamentequando o objeto for criado. Nesse caso não precisamos, por exemplo no caso da Classe Book dada acima, chamar o método setTitle ou setPrice.

    O PHP fornece uma função especial chamada __construct() para definir um construtor. Observe que a função __construct começa com dois uderscores (__)!

    
    function __construct( $par1, $par2 ) {
       $this->title = $par1;
       $this->price = $par2;
    }
    
    
    

    O exemplo a seguir usa o construtor para a classe Books dado acima e cria o objeto definindo o preço e o título do livro no momento de sua criação .

    Exemplo 2

                                
    <?php
    
    
    
    $physics = new Books( "Physics for High School", 10 );
    $maths = new Books ( "Advanced Chemistry", 15 );
    $chemistry = new Books ("Algebra", 7 );
    
    /* Obtem os valores */
    $physics->getTitle();
    $chemistry->getTitle();
    $maths->getTitle();
    
    $physics->getPrice();
    $chemistry->getPrice();
    $maths->getPrice();
       ?>
       
                        

    O resultado será:

    
    Physics for High School
      Advanced Chemistry
      Algebra
      10
      15
      7
    
    
    

    Destrutor

    Como uma função construtora, você pode definir um destrutor (função destrutora) usando a função __destruct(). QunVocê pode liberar todos os recursos com um destruidor. Se criarmos uma função __destruct(), o PHP irá automaticamente chamar esta função no final do script. Observe que a função __destruct() começa com dois underscores (sublinhados) (__)! O exemplo abaixo tem uma função __construct () que é chamada automaticamente quando você cria um objeto de uma classe e uma função __destruct () que é chamada automaticamente no final do script:
    
    
    class Fruit {
      public $name;
      public $color;
    
      function __construct($name, $color) {
        $this->name = $name;
        $this->color = $color;
      }
      function __destruct() {
        echo "The fruit is {$this->name} and the color is {$this->color}.";
      }
    }
    
    
    

    Herança

    (voltar início)

    As definições de uma classe PHP podem, opcionalmente, serem herdadas de uma definição de classe pai usando a cláusula extends. A sintaxe é a seguinte -

    
    class Child extends Parent {
       definições da classe child
    }
    
    
    
    O efeito da herança é que a classe filha (ou subclasse ou classe derivada) tem as seguintes características -
    • Possui automaticamente todas as declarações de variáveis de membro da classe pai.

    • Possui automaticamente todas as mesmas funções-membro do pai, que (por padrão) funcionarão da mesma maneira que essas funções no pai.

    O exemplo a seguir herda a classe Books e adiciona mais funcionalidade com base no requisito.

    Exemplo 2

                                
    <?php
    
    class Novel extends Books {
       var $publisher;
       
       function setPublisher($par){
          $this->publisher = $par;
       }
       
       function getPublisher(){
          echo $this->publisher. "
    "; } } ?>

    Agora, além das funções herdadas, a classe Novel mantém duas funções-membro adicionais.

    No exemplo a seguir, as funções getPrice e getTitle são substituídas para retornar alguns valores.

    Sobreposição de Funções (Overriding)

    (voltar início)

    A propriedade de sobreposição permite que as definições de funções nas classes filhas substituam as definições com o mesmo nome nas classes pais. Ou seja, em uma classe filha, podemos modificar a definição de uma função herdada da classe pai.

    No exemplo a seguir, as funções getPrice e getTitle são substituídas para retornar alguns valores.

    
    function getPrice() {
       echo $this->price . "
    "; return $this->price; } function getTitle(){ echo $this->title . "
    "; return $this->title; }

    Visibilidade de Propriedades e Métodos

    (voltar início)

    As propriedades da classe devem ser definidas como public, private, or protected (públicas, privadas ou protegidas). Se declarada usando var, a propriedade será definida como pública.

    O exemplo a seguir, extraido de php.net, mostra as diferentes formas de se declarar as propriedades de uma classe.

    Repare que, dependendo da visibilidade, o acesso a propriedade funciona ("works") ou resulta em erro ("Fatal Error")

    Exemplo 3

    Declarações das Propriedades: Visibilidades

    <?php
    /**
     * Define MyClass
     */
    class MyClass
    {
        public 
    $public 'Public';
        protected 
    $protected 'Protected';
        private 
    $private 'Private';

        function 
    printHello()
        {
            echo 
    $this->public;
            echo 
    $this->protected;
            echo 
    $this->private;
        }
    }

    $obj = new MyClass();
    echo 
    $obj->public// Works
    echo $obj->protected// Fatal Error
    echo $obj->private// Fatal Error
    $obj->printHello(); // Shows Public, Protected and Private


    /**
     * Define MyClass2
     */
    class MyClass2 extends MyClass
    {
        
    // We can redeclare the public and protected properties, but not private
        
    public $public 'Public2';
        protected 
    $protected 'Protected2';

        function 
    printHello()
        {
            echo 
    $this->public;
            echo 
    $this->protected;
            echo 
    $this->private;
        }
    }

    $obj2 = new MyClass2();
    echo 
    $obj2->public// Works
    echo $obj2->protected// Fatal Error
    echo $obj2->private// Undefined
    $obj2->printHello(); // Shows Public2, Protected2, Undefined

    ?>

Visibilidade dos Métodos

Os métodos das Classes também podem ser definidos como públicos, privados ou protegids. Métodos declarados sem qualquer visibilidade explícita são definidas como públicas.

O exemplo a seguir, extraido de php.net, mostra as diferentes formas de se declarar métodos de uma classe.

Exemplo 4 - Declarações de Métodos

<?php
/**
 * Define MyClass
 */
class MyClass
{
    
// Declare a public constructor
    
public function __construct() { }

    
// Declare a public method
    
public function MyPublic() { }

    
// Declare a protected method
    
protected function MyProtected() { }

    
// Declare a private method
    
private function MyPrivate() { }

    
// This is public
    
function Foo()
    {
        
$this->MyPublic();
        
$this->MyProtected();
        
$this->MyPrivate();
    }
}

$myclass = new MyClass;
$myclass->MyPublic(); // Works
$myclass->MyProtected(); // Fatal Error
$myclass->MyPrivate(); // Fatal Error
$myclass->Foo(); // Public, Protected and Private work


/**
 * Define MyClass2
 */
class MyClass2 extends MyClass
{
    
// This is public
    
function Foo2()
    {
        
$this->MyPublic();
        
$this->MyProtected();
        
$this->MyPrivate(); // Fatal Error
    
}
}

$myclass2 = new MyClass2;
$myclass2->MyPublic(); // Works
$myclass2->Foo2(); // Public and Protected work, not Private

class Bar 
{
    public function 
test() {
        
$this->testPrivate();
        
$this->testPublic();
    }

    public function 
testPublic() {
        echo 
"Bar::testPublic\n";
    }
    
    private function 
testPrivate() {
        echo 
"Bar::testPrivate\n";
    }
}

class 
Foo extends Bar 
{
    public function 
testPublic() {
        echo 
"Foo::testPublic\n";
    }
    
    private function 
testPrivate() {
        echo 
"Foo::testPrivate\n";
    }
}

$myFoo = new Foo();
$myFoo->test(); // Bar::testPrivate 
                // Foo::testPublic
?>

A palavra chave this

(voltar início)

Uma pseudo variável, $this, está disponível quando um método é chamado dentro de um contexto de objeto. $this é uma referência para o objeto chamador do método (normalmente o objeto ao qual o método pertence, mas pode ser outro objeto, se o método é chamado estaticamente no contexto de um objeto secundário). Isso é ilustrado no exemplo a seguir:

Exemplo 5


//exemplo 5
<?php
class A
{
    function foo()
    {
        if (isset($this)) {
            echo '$this esta definida (';
            echo get_class($this);
            echo ")\n";
        } else {
            echo "$this nao esta definida.\n";
        }
    }
}

$a = new A();
$a->foo();
?>

Em termos da nomenclatura da POO, dizemos que a palavra chave this quando usada dentro de um método faz referência ao objeto receptor. Ou seja, ela se refere ao objeto ao qual o método pertence.

Comparando Objetos

(voltar início)

Para fazermos comparação de objetos podemos usar o operador de comparação == ou o comparador de identidade === (esse operador, quando usado em variáveis verifica se elas são do mesmo tipo.

Veja mais sobre operadores no php.net.

Os objetos podem ser comparados quanto ao valor de suas propriedades e quanto "endereço" (ou posição) do objeto. Por exemplo, podemos ter duas instâncias de uma mesma classe (ou dois objetos). Eles podem ter os mesmos valores, mas possuem "endereços" distintos. Podemos ter cópias de um mesmo objeto. Veja o exemplo a seguir. Nele são comparados diferentes objetos.

Exemplo 6

//exemplo 6


<?php
function bool2str($bool) {
    if (
$bool === false) {
            return
'FALSE';
    } else {
            return
'TRUE';
    }
}

function
compareObjects(&$o1, &$o2) {
    echo
'o1 == o2 : '.bool2str($o1 == $o2)."\n";
    echo
'o1 != o2 : '.bool2str($o1 != $o2)."\n";
    echo
'o1 === o2 : '.bool2str($o1 === $o2)."\n";
    echo
'o1 !== o2 : '.bool2str($o1 !== $o2)."\n";
}

class
Flag {
    var
$flag;

    function
Flag($flag=true) {
            
$this->flag = $flag;
    }
}

class
OtherFlag {
    var
$flag;

    function
OtherFlag($flag=true) {
            
$this->flag = $flag;
    }
}

$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();

echo
"Duas instâncias da mesma classe\n";
compareObjects($o, $p);

echo
"\nDuas referências da mesma instância\n";
compareObjects($o, $q);

echo
"\nInstâncias de duas classes diferentes\n";
compareObjects($o, $r);
?>

Ao executar esse exemplo, teremos as saídas:


Duas instâncias da mesma classe
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : FALSE
o1 !== o2 : TRUE

Duas referências da mesma instância
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE

Instâncias de duas classes diferentes
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE

Clonando Objetos

(voltar início)

Nessa seção veremos duas formas de se copiar um objeto. Acompanhe os exemplos dados a seguir.

Exemplo 7

<?php
include("book.inc");

$b1 = new Book();
$b2 = $b1;
$b3 = clone $b1;
$b4 = clone $b1;
$b5 = clone $b4;
$b6 = $b4;
resulta em:<br>

?>
<html>
$b1 = new Book();<br>
$b2 = $b1;<br>
$b3 = clone $b1;<br>
$b4 = clone $b1;<br>
$b5 = clone $b4;<br>
$b6 = $b4;<br>
</html>
<?php
echo"<br>";
echo "b1 = ";var_dump($b1);
echo"<br>";
echo "b3 = ";var_dump($b2);
echo"<br>";
echo "b3 = ";var_dump($b3);
echo"<br>";

echo "b4 = ";var_dump($b4);
echo"<br>";
echo "b5 = ";var_dump($b5);
echo"<br>";
echo "b6 = ";var_dump($b6);
echo"<br>";

?>

Resulta em:


b1 = object(Book)#1 (1) { ["livro"]=> NULL}
b3 = object(Book)#1 (1) { ["livro"]=> NULL}
b3 = object(Book)#2 (1) { ["livro"]=> NULL}
b4 = object(Book)#3 (1) { ["livro"]=> NULL}
b5 = object(Book)#4 (1) { ["livro"]=> NULL}
b6 = object(Book)#3 (1) { ["livro"]=> NULL}

Exemplo 8

Complete o exemplo anterior com o trecho de código dado abaixo. Entenda o que acontece. Repare a relação dos objetos com a forma que foram criado (com igualdade ou como clones).

$b1->livro=1;
$b4->livro=2;
echo "b1->livro: ".$b1->livro;echo"<br>";
echo "b2->livro: ".$b2->livro;echo"<br>";
echo "b3->livro: ".$b3->livro;echo"<br>";
echo "b4->livro: ".$b4->livro;echo"<br>";
echo "b5->livro: ".$b5->livro;echo"<br>";
echo "b6->livro: ".$b6->livro;echo"<br>";

Neste caso, a saída será:


b1->livro: 1
b2->livro: 1
b3->livro:
b4->livro: 2
b5->livro:
b6->livro: 2

Quando o objeto é instanciado, a classe passa a ser referenciada pelo objeto, isto é, cria-se uma espaço na memória para "alocar" o objeto. As propriedades da classe passam a ter espaços específicos na memória, relacinados com o objeto. As variáveis (propriedades) apontam para o espaço reservado e portanto dizemos que elas guardam uma referência para aquele espaço. Quando copiamos o objeto com o sinal de igualdade, toda a memória reservada de um passa para o outro. Quando clonamos criamos uma outra posição de memória para o mesmo objeto. Daí os resultados apresentados no exemplo acima.

Exercícios

Exercício 1

Faça uma classe para trabalhar com números complexos. Essa classe deve conter métodos para:
  1. Retornar a parte real e imaginária do número
  2. Retornar a soma de dois números complexos
  3. Retornar o produto dois números complexos
  4. Retornar a divisão de dois números complexos
Faça um aplicativo para usar a classe. Deve-se passar os números complexos por um formulário HTML.

Exercício 2

Execute os exemplos que estão nessa página. Entenda-os e teste diferentes alternativas.

Exercício 3

Rode os exemplos com as classes Pessoa e Conta. A partir da classe Conta, crie as classes "ContaCorrente" e "ContaPoupança". Acrescente atributos e métodos a essas duas novas classes que você achar necessário. Veja o arquivo zip com as classes, clicando aqui.

Crie um aplicativo que faz uso dessas classes: crie uma (ou mais) pessoa(s) que possui(possuem) conta de banco (corrente e poupança). Faça operações de depósito e saque e mostre o saldo. Seja criativo!.

Exercício 4

Estude os exemplos do site Getting Started with OOP & PHP5. Entenda a herança da classe "Animal".

Exercício 5

Estude a classe Book.java. Veja suas características (atributos e métodos). Crie uma classe igual em PHP. Crie também a Classe ScientificBook, filha da Classe Book. Faça aplicativos para testá-las. Veja essasclasse no arquivo Book.java

Exercício 6

Estudando a classe Book, veja como fazer para comparar dois objetos. Implemente método(s) para verificar se dois objetos de uma classe são iguais. Pode ser a classe Book, ou a de números complexos ou as Classes Pessoa e Conta. No caso da classe Book, em que condições dois objetos serão iguais?

Referências



(voltar para o topo)