Skip to content

5. Os objetos

5.1. Qualquer variável pode se tornar um objeto dotado de atributos (exemple_14)


<?php

// qualquer variável pode ter atributos por definição
$obj1->attr1 = "un";
$obj1->attr2 = 100;
// exibe o objeto
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// altera o objeto
$obj1->attr2+=100;
// exibe o objeto
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// atribui o valor de objeto1 a objeto2
$obj2 = $obj1;
// altera o objeto2
$obj2->attr2 = 0;
// exibe os dois objetos
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet2=[$obj2->attr1,$obj2->attr2]\n";
// atribui a referência de objeto1 a objeto3
$obj3 = &$obj1;
// altera o objeto3
$obj3->attr2 = 10;
// exibe os dois objetos
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet3=[$obj3->attr1,$obj3->attr2]\n";
// um objeto é um dicionário?
print count($obj1)."\n";
while (list($attribut, $valeur) = each($obj1))
  print "obj1[$attribut]=$valeur\n";
// fim
exit;
?>

Resultados:

objet1=[un,100]
objet1=[un,200]
objet1=[un,0]
objet2=[un,0]
objet1=[un,10]
objet3=[un,10]
1
obj1[attr1]=un
obj1[attr2]=10

Comentários

  • linha 4: a notação $obj->attr designa o atributo attr da variável $obj. Se ele não existir, será criado, transformando assim a variável $obj em um objeto com atributos.
  • linha 13: a expressão $obj2=$obj1, quando $obj1 é um objeto, representa uma cópia de objetos por referência. Assim, $obj2 e $obj1 são referências ao mesmo objeto. O próprio objeto pode ser modificado por qualquer uma das referências.
  • linha 20: a expressão $obj3=&$obj1 atribui a $obj3 a referência (o endereço) da variável $obj1. Se $obj1 for um objeto, como é o caso aqui, a expressão anterior é equivalente a $obj3=$obj1.
  • linhas 28-29: mostram que um objeto pode ser percorrido como um dicionário. As chaves do dicionário são os nomes dos atributos e os valores do dicionário, os valores desses mesmos atributos.
  • linha 27: a função count pode ser aplicada a um objeto, mas não retorna, como seria de se esperar, o número de atributos. Portanto, um objeto apresenta semelhanças com um dicionário, mas não é um dicionário.

5.2. Uma classe Pessoa sem atributos declarados (exemple_15)


<?php

class Personne {

  // atributos da classe
  // não declarados — podem ser criados dinamicamente
  
  // método
  function identité() {
    // a princípio, utiliza atributos inexistentes
    return "[$this->prénom,$this->nom,$this->âge]";
  }
}

// teste
// os atributos são públicos e podem ser criados dinamicamente
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// chamada de um método
print "personne=" . $p->identité() . "\n";
// fim
exit;
?>

Resultados:

personne=[Paul,Langevin,48]

Comentários

  • linhas 3-13: definem uma classe Personne. Uma classe é um modelo a partir do qual se criam objetos. Uma classe é um conjunto que agrupa atributos e funções chamadas métodos. Não é obrigatório declarar os atributos.
  • linhas 9-12: o método identité exibe o valor de três atributos não declarados na classe. A palavra-chave $this designa o objeto ao qual o método é aplicado.
  • linha 17: cria-se um objeto $p do tipo Personne. A palavra-chave new serve para criar um novo objeto. A operação retorna uma referência ao objeto criado (ou seja, um endereço). São possíveis várias formas de escrita: new Pessoa(), new Pessoa, new pessoa. O nome da classe não diferencia maiúsculas de minúsculas.
  • linhas 18-20: os três atributos necessários para o método identité são criados no objeto $p.
  • linha 22: o método identité da classe Personne é aplicado ao objeto $p. No código (linhas 9-11) do método identité, $this faz referência ao mesmo objeto que $p.

5.3. A classe Pessoa com atributos declarados (exemple_16)


<?php

class Personne {

  // atributos da classe
  var $prénom;
  var $nom;
  var $âge;

  // método
  function identité() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }
}
// teste
// os atributos são públicos
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// chamada de um método
print "personne=" . $p->identité() . "\n";
// fim
exit;
?>

Resultados:

personne=[Paul,Langevin,48]

Comentários

  • linhas 6-8: os atributos da classe são declarados explicitamente com a palavra-chave var.

5.4. A classe Pessoa com um construtor (exemple_17)

Os exemplos anteriores mostravam classes Personne incomuns, como as encontradas em PHP 4. Não é recomendável seguir esses exemplos. Apresentamos agora uma classe Personne que segue as boas práticas de PHP 5:


<?php

class Personne {

// atributos da classe
  private $prénom;
  private $nom;
  private $âge;

// getters e setters
  public function getPrénom() {
    return $this->prénom;
  }

  public function getNom() {
    return $this->nom;
  }

  public function getAge() {
    return $this->âge;
  }

  public function setPrénom($prénom) {
    $this->prénom = $prénom;
  }

  public function setNom($nom) {
    $this->nom = $nom;
  }

  public function setAge($age) {
    $this->âge = $age;
  }

// construtor
  function __construct($prénom, $nom, $âge) {
    // passando pelos set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

// método toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }

}

// teste
// criação de um objeto “pessoa”
$p = new Personne("Paul", "Langevin", 48);
// identidade dessa pessoa
print "personne=$p\n";
// alteração da idade
$p->setAge(14);
// identidade da pessoa
print "personne=$p\n";
// fim
exit;
?>

Resultados:

personne=[Paul,Langevin,48]
personne=[Paul,Langevin,14]

Comentários

  • linhas 3-48: a classe Personne
  • linhas 6-8: os atributos privados (private) da classe. Esses atributos só são visíveis dentro da classe. Outras palavras-chave que podem ser utilizadas são:
  • public: torna o atributo público, visível de fora da classe
  • protected: torna o atributo protegido, visível de dentro da classe e das classes derivadas dela.
  • Como os atributos são privados, não é possível acessá-los de fora da classe. Portanto, não é possível escrever o código a seguir:
$p=new Personne() ;
$p->nom="Landru" ;

Aqui, estamos fora da classe Personne. Como o atributo nom é privado, a linha 2 está incorreta. Para inicializar os campos privados do objeto $p, há duas maneiras:

  • (continuação)
    • usar os métodos públicos set e get (o nome desses métodos pode ser qualquer um) das linhas 11 a 33. Assim, poderemos escrever:
$p=new Personne() ;
$p->setNom("Landru") ;
  • (continuação)
    • usar o construtor das linhas 36 a 41. Nesse caso, escreveremos:
$p=new Personne("Michel","Landru",44) ;

A sintaxe acima chama automaticamente o método da classe Personne denominado __construct.

  • linha 54: esta linha exibe a pessoa $p na forma de uma sequência de caracteres. Para isso, é utilizado o método da classe Personne, chamado __toString.

5.5. A classe Pessoa com verificação de validade no construtor (exemple_18)

O construtor de uma classe é o local adequado para verificar se os valores de inicialização do objeto estão corretos. No entanto, um objeto também pode ser inicializado por meio de seus métodos set ou equivalentes. Para evitar repetir as mesmas verificações em dois locais diferentes, elas serão colocadas nos métodos set. Se um valor de inicialização de um objeto for incorreto, será lançada uma exceção. Veja um exemplo:


<?php

class Personne {

// atributos da classe
  private $prénom;
  private $nom;
  private $âge;
  
// getters e setters
  public function getPrénom() {
    return $this->prénom;
  }

  public function getNom() {
    return $this->nom;
  }

  public function getAge() {
    return $this->âge;
  }

  public function setPrénom($prénom) {
    // o nome deve ser diferente de vazio
    if (!preg_match("/^\s*(.+?)\s*$/", $prénom, $champs)) {
      throw new Exception("Le prénom doit être non vide");
    } else {
      $this->prénom = $champs[1];
    }
  }

  public function setNom($nom) {
    // o sobrenome não pode estar vazio
    if (!preg_match("/^\s*(.+?)\s*$/", $nom, $champs)) {
      throw new Exception("Le nom doit être non vide");
    } else {
      $this->nom = $champs[1];
    }
  }

  public function setAge($âge) {
    // a idade deve ser válida
    if (!preg_match("/^\s*(\d+)\s*$/", $âge, $champs)) {
      throw new Exception("L'âge doit être un entier positif ou nul");
    } else {
      $this->âge = $champs[1];
    }
  }

// construtor
  function __construct($prénom, $nom, $âge) {
    // utilizamos os set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // método toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }
}

// teste
// criação de um objeto Pessoa
$p = new Personne("Paul", "Langevin", 48);
// identidade dessa pessoa
print "personne=$p\n";
// criação de um objeto Pessoa com erro
try {
  $p = new Personne("xx", "yy", "zz");
} catch (Exception $e) {
  print $e->getMessage();
}
// fim
exit;
?>

Resultados:

personne=[Paul,Langevin,48]
L'âge doit être un entier positif ou nul

Comentários

  • linhas 23-30: inicialização do atributo prénom e verificação do valor de inicialização
  • linha 25: uso de uma expressão regular. O nome é uma sequência de um ou mais caracteres, eventualmente seguida ou precedida por espaços.
  • linha 26: se o sobrenome estiver vazio, é lançada uma exceção; caso contrário, o nome é armazenado (linha 28)
  • linha 66: uso do construtor da classe Personne
  • linha 68: uso do método __toString da classe Personne
  • linhas 70-74: tratamento da eventual exceção lançada pelo construtor da classe Personne.

5.6. Adicionar um método que funcione como segundo construtor (exemple_19)

No PHP 5, não é possível ter vários construtores com parâmetros diferentes que permitam construir um objeto de diversas maneiras. Portanto, é possível utilizar métodos que funcionam como construtores:


<?php

class Personne {

// atributos da classe
  private $prénom;
  private $nom;
  private $âge;
  
// getters e setters
  public function getPrénom() {
    return $this->prénom;
  }

….

// construtor
  function __construct($prénom, $nom, $âge) {
    // utilizando os set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // método
  public function initWithPersonne($p) {
    // inicializa o objeto atual com uma pessoa $p
    $this->__construct($p->prénom, $p->nom, $p->âge);
  }

  // método toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }

}

// teste
// criação de um objeto Pessoa
$p = new Personne("Paul", "Langevin", 48);
// identidade dessa pessoa
print "personne=$p\n";
// criação de uma segunda pessoa
$p2 = new Personne("Laure", "Adeline", 67);
// inicialização da primeira com os valores da segunda
$p->initWithPersonne($p2);
// verificação
print "personne=$p\n";
// fim
exit;
?>

Resultados:

personne=[Paul,Langevin,48]
personne=[Laure,Adeline,67]

Comentários

  • linhas 26-29: o método initWithPersonne permite atribuir ao objeto atual os valores dos atributos de outro objeto Personne. Aqui, ele utiliza o construtor __construct, mas isso não é obrigatório.

5.7. Uma matriz de objetos Pessoa (exemple_20)

O exemplo a seguir mostra que é possível ter matrizes de objetos.


<?php

class Personne {

// atributos da classe
  private $prénom;
  private $nom;
  private $âge;
  
// getters e setters
  public function getPrénom() {
    return $this->prénom;
  }

...

// construtor
  function __construct($prénom, $nom, $âge) {
    // passamos pelos set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // método
  public function initWithPersonne($p) {
….
  }

  // método toString
  function __toString() {
    ...
  }

}

// teste
// criação de uma tabela de objetos Pessoa
$groupe = array(new Personne("Paul", "Langevin", 48), new Personne("Sylvie", "Lefur", 70));

// identidade dessas pessoas
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// fim
exit;
?>

Resultados:

groupe[0]=[Paul,Langevin,48]
groupe[1]=[Sylvie,Lefur,70]

Comentários

  • linha 39: criação de uma tabela com 2 pessoas
  • linha 42: percorrer a tabela
  • linha 43: $groupe[$i] é um objeto do tipo Personne. O método __toString é utilizado para exibi-lo.

5.8. Criação de uma classe derivada da classe Pessoa (exemple_21)


<?php

class Personne {

// atributos da classe
  private $prénom;
  private $nom;
  private $âge;
  
// getters e setters
  public function getPrénom() {
    return $this->prénom;
  }
...

// construtor
  function __construct($prénom, $nom, $âge) {
    // utilizamos os set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // método
  public function initWithPersonne($p) {
    // inicializa o objeto atual com uma pessoa $p
    $this->__construct($p->prénom, $p->nom, $p->âge);
  }

  // método toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }

}

// uma classe derivada de Pessoa
class Enseignant extends Personne {

  // atributos
  private $discipline;   // disciplina lecionada

  // getters e setters

  public function getDiscipline() {
    return $this->discipline;
  }

  public function setDiscipline($discipline) {
    $this->discipline = $discipline;
  }

  // construtor

  public function __construct($prénom, $nom, $âge, $discipline) {
    // atributos do pai
    parent::__construct($prénom, $nom, $âge);
    // outros atributos
    $this->setDiscipline($discipline);
  }

  // sobrecarregamento da função __toString da classe pai
  public function __toString() {
    return "[" . parent::__toString() . ",$this->discipline]";
  }

}

// teste
// criação de uma tabela de objetos Pessoa e derivados
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70));

// identidade dessas pessoas
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// fim
exit;
?>

Resultados:

groupe[0]=[[Paul,Langevin,48],anglais]
groupe[1]=[Sylvie,Lefur,70]

Comentários

  • linhas 3-35: a classe Personne
  • linha 38: a classe Enseignant deriva (extends) da classe Personne. A classe derivada Enseignant herda os atributos e métodos de sua classe pai.
  • linha 41: a classe Enseignant adiciona um novo atributo, discipline, que é exclusivo dela
  • linha 55: o construtor da classe Enseignant recebe 4 parâmetros
    • 3 para inicializar sua classe pai (nome, sobrenome, idade)
    • 1 para sua própria inicialização (matéria)
  • linha 57: a classe derivada tem acesso aos métodos e construtores de sua classe pai por meio da palavra-chave parent::. Aqui, passamos os parâmetros (nome, sobrenome, idade) para o construtor da classe pai.
  • linha 64: o método __toString da classe derivada utiliza o método __toString da classe pai.
  • linha 71: um array contendo um objeto Enseignant e um objeto Personne.
  • linha 74: é feito um loop pelos elementos da matriz
  • linha 75: o método __toString de cada elemento $groupe[$i] será chamado. A classe Personne possui um método __toString. A classe Enseignant possui dois: o de sua classe pai e o próprio. Podemos nos perguntar qual deles será chamado. A execução mostra que foi chamado o da classe Enseignant. É sempre assim: quando um método é chamado em um objeto, ele é procurado na seguinte ordem: no próprio objeto, em sua classe pai, se houver, depois na classe pai da classe pai, e assim por diante… A busca é interrompida assim que o método é encontrado.

5.9. Criação de uma segunda classe derivada da classe Pessoa (exemple_22)

O exemplo a seguir cria uma classe Etudiant derivada da classe Personne:


<?php

class Personne {

// atributos da classe
  private $prénom;
  private $nom;
  private $âge;

// getters e setters
  public function getPrénom() {
    return $this->prénom;
  }
...

// construtor
  function __construct($prénom, $nom, $âge) {
    // utilizamos os set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // método
  public function initWithPersonne($p) {
    // inicializa o objeto atual com uma pessoa $p
    ...
  }

  // método toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }

}

// uma classe derivada de pessoa
class Enseignant extends Personne {

  // atributos
  private $discipline;   // disciplina lecionada

  // getters e setters
...

  // construtor

  public function __construct($prénom, $nom, $âge, $discipline) {
    // atributos do pai
    parent::__construct($prénom, $nom, $âge);
    // outros atributos
    $this->setDiscipline($discipline);
  }

  // sobrecarregamento da função _identité__toString da classe pai
  public function __toString() {
    return "[" . parent::__toString() . ",$this->discipline]";
  }

}

// uma classe derivada de Pessoa
class Etudiant extends Personne {

  // atributos
  private $formation;   // disciplina lecionada

  // getters e setters

  public function getFormation() {
    return $this->formation;
  }

  public function setFormation($formation) {
    $this->formation = $formation;
  }

  // construtor

  public function __construct($prénom, $nom, $âge, $formation) {
    // atributos do pai
    parent::__construct($prénom, $nom, $âge);
    // outros atributos
    $this->setFormation($formation);
  }

  // sobrecarregamento da função __toString da classe pai
  public function __toString() {
    return "[" . parent::__toString() . ",$this->formation]";
  }

}

// teste
// criação de uma matriz de objetos “pessoa” e derivados
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70), new Etudiant("Steve", "Boer", 23, "iup2 qualité"));

// identidade dessas pessoas
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// fim
exit;
?>

Resultados:

groupe[0]=[[Paul,Langevin,48],anglais]
groupe[1]=[Sylvie,Lefur,70]
groupe[2]=[[Steve,Boer,23],iup2 qualité]

5.10. As interfaces (exemple_23)

Uma interface é uma estrutura que define protótipos de métodos. Uma classe que implementa uma interface define o código de todos os métodos da interface.


<?php

// uma interface
interface IExemple {
  function ajouter($i, $j);

  function soustraire($i, $j);
}

// implementação 1 da interface
class Classe1 implements IExemple {

  public function ajouter($a, $b) {
    return $a + $b + 10;
  }

  public function soustraire($a, $b) {
    return $a - $b + 20;
  }

}

// implementação 2 da interface
class Classe2 implements IExemple {

  public function ajouter($a, $b) {
    return $a + $b + 100;
  }

  public function soustraire($a, $b) {
    return $a - $b + 200;
  }

}

// função
function calculer($a, $b, IExemple $interface) {
  print $interface->ajouter($a, $b)."\n";
  print $interface->soustraire($a, $b)."\n";
}

// ------------------- main
// criação de 2 objetos dos tipos Classe1 e Classe2
$c1 = new Classe1();
$c2 = new Classe2();
// chamada da função calcular
calculer(4, 3, $c1);
calculer(14, 13, $c2);
?>

Resultados

17
21
127
201

Comentários

  • linhas 4-8: a interface IExemple define dois métodos: a função ajouter (linha 5) e a função soustraire (linha 7). A interface não define o código desses métodos. São as classes que implementam a interface que farão isso.
  • linha 11: a classe Classe1 implementa a interface IExemple. Portanto, ela define um código para os métodos ajouter (linha 13) e soustraire (linha 17).
  • linhas 24-34: o mesmo vale para a classe Classe2
  • linha 37: o método calculer aceita três parâmetros: dois inteiros, $a e $b, e um objeto $interface que implementa a interface IExemple. Seria possível escrever function calcular($a, $b, $interface) sem indicar o tipo IExemple do parâmetro $interface. Ao indicá-lo, permite-se que o interpretador PHP verifique se o parâmetro efetivo é, de fato, um objeto que implementa a interface IExemple.
  • linhas 38-39: uso dos métodos ajouter e soustraire do objeto $interface. Como esse objeto implementa a interface IExemple, sabemos que ele possui esses dois métodos.
  • linhas 44-45: criação de dois objetos de tipos diferentes, mas que implementam a interface IExemple.
  • linha 47: passa-se para a função calculer o objeto $c1, do tipo Classe1, que implementa a interface IExemple.
  • linha 48: passa-se para a função calculer, sendo que o objeto $c2, do tipo Classe2, implementa a interface IExemple.