5. Objetos
5.1. Qualquer variável pode tornar-se um objeto com atributos (exemplo_14)
<?php
// any variable can have attributes by construction
$obj1->attr1 = "un";
$obj1->attr2 = 100;
// displays the
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// modify object
$obj1->attr2+=100;
// displays the
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// assigns the value of object1 to object2
$obj2 = $obj1;
// modify obj2
$obj2->attr2 = 0;
// displays both objects
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet2=[$obj2->attr1,$obj2->attr2]\n";
// assigns the reference from object1 to object3
$obj3 = &$obj1;
// modify obj3
$obj3->attr2 = 10;
// displays both objects
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet3=[$obj3->attr1,$obj3->attr2]\n";
// is an object a dictionary?
print count($obj1)."\n";
while (list($attribut, $valeur) = each($obj1))
print "obj1[$attribut]=$valeur\n";
// end
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 refere-se ao atributo attr da variável $obj. Se não existir, é criado, tornando assim a variável $obj um objeto com atributos.
- linha 13: a expressão $obj2 = $obj1, quando $obj1 é um objeto, constitui 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 referência (endereço) da variável $obj1 a $obj3. Se $obj1 for um objeto, como é o caso aqui, a expressão anterior é equivalente a $obj3=$obj1.
- Linhas 28–29: demonstram 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 são os valores desses mesmos atributos.
- Linha 27: A função count pode ser aplicada a um objeto, mas não retorna, como seria de esperar, o número de atributos. Portanto, um objeto partilha semelhanças com um dicionário, mas não é um.
5.2. Uma classe Pessoa sem atributos declarados (exemplo_15)
<?php
class Personne {
// class attributes
// undeclared - can be created dynamically
// method
function identité() {
// a priori, uses non-existent attributes
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// attributes are public and can be created dynamically
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// method call
print "personne=" . $p->identité() . "\n";
// end
exit;
?>
Resultados:
Comentários
- linhas 3–13: definem uma classe Person. Uma classe é um modelo utilizado para criar objetos. Uma classe é um conjunto de atributos e funções denominadas métodos. Os atributos não têm de ser declarados.
- Linhas 9–12: O método identity exibe os valores de três atributos não declarados na classe. A palavra-chave $this refere-se ao objeto ao qual o método é aplicado.
- Linha 17: É criado um objeto $p do tipo Pessoa. A palavra-chave new é utilizada para criar um novo objeto. A operação devolve uma referência ao objeto criado (ou seja, um endereço). São possíveis várias notações: new Pessoa(), new Pessoa, new pessoa. O nome da classe não distingue maiúsculas de minúsculas.
- Linhas 18–20: Os três atributos exigidos pelo método identity são criados no objeto $p.
- Linha 22: o método identity da classe Person é aplicado ao objeto $p. No código (linhas 9–11) do método identity, $this refere-se ao mesmo objeto que $p.
5.3. A classe Person com atributos declarados (exemplo_16)
<?php
class Personne {
// class attributes
var $prénom;
var $nom;
var $âge;
// method
function identité() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// attributes are public
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// method call
print "personne=" . $p->identité() . "\n";
// end
exit;
?>
Resultados:
Comentários
5.4. A classe Pessoa com um construtor (exemplo_17)
Os exemplos anteriores mostraram classes Person pouco comuns, tal como poderiam ter sido encontradas no PHP 4. Não é recomendável seguir estes exemplos. Apresentamos agora uma classe Person que segue as melhores práticas do PHP 5:
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and 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;
}
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// creation of a person object
$p = new Personne("Paul", "Langevin", 48);
// identity of this person
print "personne=$p\n";
// we change the age
$p->setAge(14);
// identity of the person
print "personne=$p\n";
// end
exit;
?>
Resultados:
Comentários
- linhas 3-48: a classe Pessoa
- linhas 6-8: os atributos privados da classe. Estes atributos só são visíveis dentro da classe. Outras palavras-chave que podem ser utilizadas são:
- public: torna o atributo um atributo público, visível a partir do exterior da classe
- protected: torna o atributo um atributo protegido, visível de dentro da classe e das suas classes derivadas.
- Como os atributos são privados, não podem ser acedidos a partir do exterior da classe. Por conseguinte, não podemos escrever o seguinte código:
Aqui, estamos fora da classe Person. Como o atributo name é privado, a linha 2 está incorreta. Para inicializar os campos privados do objeto $p, existem duas maneiras:
- (continuação)
- utilizar os métodos públicos set e get (os nomes destes métodos podem ser quaisquer) das linhas 11–33. Podemos então escrever:
- (continuação)
- Utilize o construtor das linhas 36–41. Escreveríamos então:
O código acima chama automaticamente o método da classe Person chamado __construct.
- Linha 54: Esta linha apresenta a Person $p como uma cadeia de caracteres. Para tal, é utilizado o método da classe Person denominado __toString.
5.5. A classe Person com verificações de validade no construtor (exemplo_18)
O construtor de uma classe é o local certo para verificar se os valores de inicialização do objeto estão corretos. No entanto, um objeto também pode ser inicializado através dos seus métodos set ou equivalentes. Para evitar a duplicação das mesmas verificações em dois locais diferentes, vamos colocá-las dentro dos métodos set. Se for detetado que o valor de inicialização de um objeto está incorreto, será lançada uma exceção. Aqui está um exemplo:
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and 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) {
// first name must be non-empty
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) {
// name must be non-empty
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) {
// age must be valid
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];
}
}
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// creation of a Personne object
$p = new Personne("Paul", "Langevin", 48);
// identity of this person
print "personne=$p\n";
// creation of an erroneous Person object
try {
$p = new Personne("xx", "yy", "zz");
} catch (Exception $e) {
print $e->getMessage();
}
// end
exit;
?>
Resultados:
Comentários
- linhas 23-30: inicialização do atributo first_name e verificação do valor de inicialização
- linha 25: utilização de uma expressão regular. O nome próprio é uma sequência de um ou mais caracteres, possivelmente seguida ou precedida por espaços.
- linha 26: se o apelido estiver vazio, é lançada uma exceção; caso contrário, o nome próprio é guardado (linha 28)
- linha 66: utilização do construtor da classe Person
- linha 68: utilização do método __toString da classe Person
- Linhas 70–74: Tratamento de qualquer exceção lançada pelo construtor da classe Person.
5.6. Adicionar um método que atua como um segundo construtor (exemplo_19)
No PHP 5, não é possível ter múltiplos construtores com parâmetros diferentes que permitam que um objeto seja construído de várias maneiras. Podemos, portanto, utilizar métodos que atuam como construtores:
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
….
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
// initializes the current object with a person $p
$this->__construct($p->prénom, $p->nom, $p->âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// creation of a Personne object
$p = new Personne("Paul", "Langevin", 48);
// identity of this person
print "personne=$p\n";
// creation of a second person
$p2 = new Personne("Laure", "Adeline", 67);
// initialization of the first with the values of the second
$p->initWithPersonne($p2);
// check
print "personne=$p\n";
// end
exit;
?>
Resultados:
Comentários
- linhas 26-29: O método initWithPerson permite atribuir os valores dos atributos de outro objeto Person ao objeto atual. Aqui, ele chama o construtor __construct, mas isso não é obrigatório.
5.7. Uma matriz de objetos Person (exemplo_20)
O exemplo seguinte mostra que é possível ter matrizes de objetos.
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
...
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
….
}
// method toString
function __toString() {
...
}
}
// test
// create an array of Personne objects
$groupe = array(new Personne("Paul", "Langevin", 48), new Personne("Sylvie", "Lefur", 70));
// identity of these persons
for ($i = 0; $i < count($groupe); $i++)
print "groupe[$i]=$groupe[$i]\n";
// end
exit;
?>
Resultados:
Comentários
- linha 39: criação de uma matriz com 2 pessoas
- linha 42: iteração pela matriz
- linha 43: $group[$i] é um objeto do tipo Pessoa. O método __toString é utilizado para o exibir.
5.8. Criação de uma classe derivada da classe Pessoa (exemplo_21)
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
...
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
// initializes the current object with a person $p
$this->__construct($p->prénom, $p->nom, $p->âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// a class derived from Personne
class Enseignant extends Personne {
// attributes
private $discipline; // d// subject taught
// getter and setter
public function getDiscipline() {
return $this->discipline;
}
public function setDiscipline($discipline) {
$this->discipline = $discipline;
}
// manufacturer
public function __construct($prénom, $nom, $âge, $discipline) {
// parent attributes
parent::__construct($prénom, $nom, $âge);
// other attributes
$this->setDiscipline($discipline);
}
// overloads the __toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->discipline]";
}
}
// test
// creation of an array of Personne and derived objects
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70));
// identity of these persons
for ($i = 0; $i < count($groupe); $i++)
print "groupe[$i]=$groupe[$i]\n";
// end
exit;
?>
Resultados:
Comentários
- linhas 3-35: a classe Pessoa
- linha 38: a classe Professor estende a classe Pessoa. A classe derivada Professor herda os atributos e métodos da sua classe pai.
- linha 41: a classe Professor adiciona um novo atributo, disciplina, que é específico desta
- linha 55: o construtor da classe Professor recebe 4 parâmetros
- 3 para inicializar a sua classe pai (primeiro_nome, apelido, idade)
- 1 para a sua própria inicialização (disciplina)
- linha 57: a classe derivada tem acesso aos métodos e construtores da sua classe pai através da palavra-chave parent::. Aqui, passamos os parâmetros (first_name, last_name, age) 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 Teacher e um objeto Person.
- linha 74: percorremos os elementos da matriz
- linha 75: será chamado o método __toString de cada elemento $group[$i]. A classe Person possui um método __toString. A classe Teacher possui dois: o da sua classe pai e o seu próprio. Poder-se-á perguntar qual deles será chamado. A execução mostra que foi o método da classe Teacher que foi chamado. É sempre assim: quando um método é chamado num objeto, ele é procurado na seguinte ordem: no próprio objeto, na sua classe pai, se tiver uma, depois na classe pai da classe pai, e assim por diante… A pesquisa pára assim que o método é encontrado.
5.9. Criar uma segunda classe derivada da classe Pessoa (exemplo_22)
O exemplo seguinte cria uma classe Student derivada da classe Person:
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
...
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
// initializes the current object with a person $p
...
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// a class derived from personne
class Enseignant extends Personne {
// attributes
private $discipline; // d// subject taught
// getter and setter
...
// manufacturer
public function __construct($prénom, $nom, $âge, $discipline) {
// parent attributes
parent::__construct($prénom, $nom, $âge);
// other attributes
$this->setDiscipline($discipline);
}
// overloads the _identité__toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->discipline]";
}
}
// a class derived from Personne
class Etudiant extends Personne {
// attributes
private $formation; // d// subject taught
// getter and setter
public function getFormation() {
return $this->formation;
}
public function setFormation($formation) {
$this->formation = $formation;
}
// manufacturer
public function __construct($prénom, $nom, $âge, $formation) {
// parent attributes
parent::__construct($prénom, $nom, $âge);
// other attributes
$this->setFormation($formation);
}
// overloads the __toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->formation]";
}
}
// test
// creation of a table of person objects and derivatives
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70), new Etudiant("Steve", "Boer", 23, "iup2 qualité"));
// identity of these persons
for ($i = 0; $i < count($groupe); $i++)
print "groupe[$i]=$groupe[$i]\n";
// end
exit;
?>
Resultados:
groupe[0]=[[Paul,Langevin,48],anglais]
groupe[1]=[Sylvie,Lefur,70]
groupe[2]=[[Steve,Boer,23],iup2 qualité]
5.10. Interfaces (exemplo_23)
Uma interface é uma estrutura que define protótipos de métodos. Uma classe que implementa uma interface define o código para todos os métodos da interface.
<?php
// an interface
interface IExemple {
function ajouter($i, $j);
function soustraire($i, $j);
}
// interface implementation 1
class Classe1 implements IExemple {
public function ajouter($a, $b) {
return $a + $b + 10;
}
public function soustraire($a, $b) {
return $a - $b + 20;
}
}
// interface implementation 2
class Classe2 implements IExemple {
public function ajouter($a, $b) {
return $a + $b + 100;
}
public function soustraire($a, $b) {
return $a - $b + 200;
}
}
// function
function calculer($a, $b, IExemple $interface) {
print $interface->ajouter($a, $b)."\n";
print $interface->soustraire($a, $b)."\n";
}
// ------------------- hand
// creation of 2 objects of type Class1 and Class2
$c1 = new Classe1();
$c2 = new Classe2();
// call the calculate function
calculer(4, 3, $c1);
calculer(14, 13, $c2);
?>
Resultados
Comentários
- Linhas 4–8: A interface IExample define dois métodos: a função add (linha 5) e a função subtract (linha 7). A interface não define o código para estes métodos. As classes que implementam a interface farão isso.
- Linha 11: A classe Class1 implementa a interface IExample. Por conseguinte, define o código para o método add (linha 13) e para o método subtract (linha 17).
- Linhas 24–34: O mesmo se aplica à classe Class2.
- Linha 37: O método
*calculerrecebe três parâmetros: dois inteiros,*$a*e$b*, e um objeto*$interfaceque implementa a interface*IExample. Poderíamos ter escritofunction calculate($a, $b, $interface)sem especificar o tipoIExampledo parâmetro*$interface*. Ao especificá-lo, permitimos que o interpretador PHP verifique se o parâmetro real é, de facto, um objeto que implementa a interface*IExample*. - linhas 38–39: utilização dos métodos add e subtract do objeto $interface. Como este implementa a interface IExample, sabemos que possui estes dois métodos.
- Linhas 44–45: Criação de dois objetos de tipos diferentes, ambos implementando a interface IExample.
- Linha 47: Passamos o objeto $c1 do tipo Class1, que implementa a interface IExample, para a função calculate.
- Linha 48: O objeto $c2 do tipo Class2, que implementa a interface IExample, é passado para a função calculate.