Skip to content

5. Gli oggetti

5.1. Qualsiasi variabile può diventare un oggetto dotato di attributi (exemple_14)


<?php

// ogni variabile può avere attributi per definizione
$obj1->attr1 = "un";
$obj1->attr2 = 100;
// visualizza l'oggetto
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// modifica l'oggetto
$obj1->attr2+=100;
// visualizza l'oggetto
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// assegna il valore di oggetto1 a oggetto2
$obj2 = $obj1;
// modifica obj2
$obj2->attr2 = 0;
// visualizza entrambi gli oggetti
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet2=[$obj2->attr1,$obj2->attr2]\n";
// assegna il riferimento di oggetto1 a oggetto3
$obj3 = &$obj1;
// modifica obj3
$obj3->attr2 = 10;
// visualizza entrambi gli oggetti
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet3=[$obj3->attr1,$obj3->attr2]\n";
// un oggetto è un dizionario?
print count($obj1)."\n";
while (list($attribut, $valeur) = each($obj1))
  print "obj1[$attribut]=$valeur\n";
// fine
exit;
?>

Risultati:

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

Commenti

  • riga 4: la notazione $obj->attr indica l'attributo attr della variabile $obj. Se non esiste, viene creato, trasformando così la variabile $obj in un oggetto con attributi.
  • riga 13: l'espressione $obj2=$obj1, quando $obj1 è un oggetto, rappresenta una copia di oggetti per riferimento. Pertanto, $obj2 e $obj1 sono riferimenti allo stesso oggetto. L’oggetto stesso può essere modificato tramite uno qualsiasi dei due riferimenti.
  • riga 20: l'espressione $obj3=&$obj1 assegna a $obj3 il riferimento (l'indirizzo) della variabile $obj1. Se $obj1 è un oggetto, come in questo caso, l'espressione precedente è equivalente a $obj3=$obj1.
  • righe 28-29: mostrano che un oggetto può essere iterato come un dizionario. Le chiavi del dizionario sono i nomi degli attributi e i valori del dizionario sono i valori di questi stessi attributi.
  • riga 27: la funzione count può essere applicata a un oggetto ma non restituisce, come ci si sarebbe potuto aspettare, il numero di attributi. Pertanto, un oggetto presenta delle somiglianze con un dizionario ma non ne è uno.

5.2. Una classe Persona senza attributi dichiarati (exemple_15)


<?php

class Personne {

  // attributi della classe
  // non dichiarati - possono essere creati dinamicamente
  
  // metodo
  function identité() {
    // a prima vista, utilizza attributi inesistenti
    return "[$this->prénom,$this->nom,$this->âge]";
  }
}

// test
// gli attributi sono pubblici e possono essere creati dinamicamente
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// chiamata di un metodo
print "personne=" . $p->identité() . "\n";
// fine
exit;
?>

Risultati:

personne=[Paul,Langevin,48]

Commenti

  • righe 3-13: definiscono una classe Personne. Una classe è uno stampo a partire dal quale si creano gli oggetti. Una classe è un insieme che raggruppa attributi e funzioni chiamate metodi. Non è obbligatorio dichiarare gli attributi.
  • righe 9-12: il metodo identité visualizza il valore di tre attributi non dichiarati nella classe. La parola chiave $this indica l’oggetto a cui si applica il metodo.
  • riga 17: si crea un oggetto $p di tipo Personne. La parola chiave new serve a creare un nuovo oggetto. L'operazione restituisce un riferimento all'oggetto creato (quindi un indirizzo). Sono possibili diverse sintassi: new Personne(), new Personne, new personne. Il nome della classe non fa distinzione tra maiuscole e minuscole.
  • righe 18-20: i tre attributi necessari al metodo identité vengono creati nell’oggetto $p.
  • riga 22: il metodo identité della classe Personne viene applicato all’oggetto $p. Nel codice (righe 9-11) del metodo identité, $this fa riferimento allo stesso oggetto di $p.

5.3. La classe Persona con attributi dichiarati (exemple_16)


<?php

class Personne {

  // attributi della classe
  var $prénom;
  var $nom;
  var $âge;

  // metodo
  function identité() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }
}
// test
// gli attributi sono pubblici
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// chiamata di un metodo
print "personne=" . $p->identité() . "\n";
// fine
exit;
?>

Risultati:

personne=[Paul,Langevin,48]

Commenti

  • righe 6-8: gli attributi della classe sono dichiarati esplicitamente con la parola chiave var.

5.4. La classe Persona con un costruttore (exemple_17)

Gli esempi precedenti mostravano classi Personne insolite, come quelle che si potevano trovare in PHP 4. Non è consigliabile seguire questi esempi. Presentiamo ora una classe Personne conforme alle buone pratiche di PHP 5:


<?php

class Personne {

// attributi della classe
  private $prénom;
  private $nom;
  private $âge;

// getter e setter
  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;
  }

// costruttore
  function __construct($prénom, $nom, $âge) {
    // si passa attraverso i set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

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

}

// test
// creazione di un oggetto persona
$p = new Personne("Paul", "Langevin", 48);
// identità di questa persona
print "personne=$p\n";
// si modifica l'età
$p->setAge(14);
// identità della persona
print "personne=$p\n";
// fine
exit;
?>

Risultati:

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

Commenti

  • righe 3-48: la classe Personne
  • righe 6-8: gli attributi privati (private) della classe. Questi attributi sono visibili solo all'interno della classe. Le altre parole chiave utilizzabili sono:
  • public: rende l'attributo pubblico, visibile dall'esterno della classe
  • protected: rende l'attributo protetto, visibile dall'interno della classe e dalle classi da essa derivate.
  • Poiché gli attributi sono privati, non è possibile accedervi dall’esterno della classe. Non è quindi possibile scrivere il seguente codice:
$p=new Personne() ;
$p->nom="Landru" ;

Qui ci si trova all'esterno della classe Personne. Poiché l'attributo nom è privato, la riga 2 è errata. Per inizializzare i campi privati dell'oggetto $p, ci sono due modi:

  • (continua)
    • utilizzare i metodi pubblici set e get (il nome di questi metodi può essere qualsiasi) delle righe 11-33. Si potrà quindi scrivere:
$p=new Personne() ;
$p->setNom("Landru") ;
  • (continua)
    • utilizzare il costruttore delle righe 36-41. Si scriverà quindi:
$p=new Personne("Michel","Landru",44) ;

Il codice sopra riportato richiama automaticamente il metodo della classe Personne denominato __construct.

  • riga 54: questa riga visualizza la persona $p sotto forma di stringa di caratteri. A tal fine, viene utilizzato il metodo della classe Personne denominato __toString.

5.5. La classe Persona con controllo di validità nel costruttore (exemple_18)

Il costruttore di una classe è il luogo ideale per verificare che i valori di inizializzazione dell’oggetto siano corretti. Tuttavia, un oggetto può essere inizializzato anche tramite i propri metodi set o equivalenti. Per evitare di inserire le stesse verifiche in due punti diversi, queste ultime verranno inserite nei metodi set. Se un valore di inizializzazione di un oggetto risulta errato, verrà generata un’eccezione. Ecco un esempio:


<?php

class Personne {

// attributi della classe
  private $prénom;
  private $nom;
  private $âge;
  
// getter e setter
  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) {
    // il nome deve essere diverso da vuoto
    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) {
    // il cognome deve essere non vuoto
    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) {
    // l'età deve essere valida
    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];
    }
  }

// costruttore
  function __construct($prénom, $nom, $âge) {
    // si utilizzano i set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

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

// test
// creazione di un oggetto Persona
$p = new Personne("Paul", "Langevin", 48);
// identità di questa persona
print "personne=$p\n";
// creazione errata di un oggetto Persona
try {
  $p = new Personne("xx", "yy", "zz");
} catch (Exception $e) {
  print $e->getMessage();
}
// fine
exit;
?>

Risultati:

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

Commenti

  • righe 23-30: inizializzazione dell'attributo prénom e verifica del valore di inizializzazione
  • riga 25: utilizzo di un'espressione regolare. Il nome è una sequenza di uno o più caratteri, eventualmente preceduta o seguita da spazi.
  • riga 26: se il cognome è vuoto, viene generata un'eccezione; altrimenti il nome viene memorizzato (riga 28)
  • riga 66: utilizzo del costruttore della classe Personne
  • riga 68: utilizzo del metodo __toString della classe Personne
  • righe 70-74: gestione dell'eventuale eccezione generata dal costruttore della classe Personne.

5.6. Aggiunta di un metodo che funge da secondo costruttore (exemple_19)

In PHP 5, non è possibile avere più costruttori con parametri diversi che consentano di creare un oggetto in vari modi. È quindi possibile utilizzare metodi che fungono da costruttori:


<?php

class Personne {

// attributi della classe
  private $prénom;
  private $nom;
  private $âge;
  
// getter e setter
  public function getPrénom() {
    return $this->prénom;
  }

….

// costruttore
  function __construct($prénom, $nom, $âge) {
    // si passa tramite i set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // metodo
  public function initWithPersonne($p) {
    // inizializza l'oggetto corrente con una persona $p
    $this->__construct($p->prénom, $p->nom, $p->âge);
  }

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

}

// test
// creazione di un oggetto Persona
$p = new Personne("Paul", "Langevin", 48);
// identità di questa persona
print "personne=$p\n";
// creazione di una seconda persona
$p2 = new Personne("Laure", "Adeline", 67);
// inizializzazione della prima con i valori della seconda
$p->initWithPersonne($p2);
// verifica
print "personne=$p\n";
// fine
exit;
?>

Risultati:

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

Commenti

  • righe 26-29: il metodo initWithPersonne consente di assegnare all'oggetto corrente i valori degli attributi di un altro oggetto Personne. In questo caso, richiama il costruttore __construct, ma ciò non è obbligatorio.

5.7. Un array di oggetti Persona (exemple_20)

L'esempio seguente mostra che è possibile avere array di oggetti.


<?php

class Personne {

// attributi della classe
  private $prénom;
  private $nom;
  private $âge;
  
// getter e setter
  public function getPrénom() {
    return $this->prénom;
  }

...

// costruttore
  function __construct($prénom, $nom, $âge) {
    // si passa attraverso i set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // metodo
  public function initWithPersonne($p) {
….
  }

  // metodo toString
  function __toString() {
    ...
  }

}

// test
// creazione di un array di oggetti Persona
$groupe = array(new Personne("Paul", "Langevin", 48), new Personne("Sylvie", "Lefur", 70));

// identità di queste persone
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// fine
exit;
?>

Risultati:

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

Commenti

  • riga 39: creazione di una tabella con 2 persone
  • riga 42: iterazione sull'array
  • riga 43: $groupe[$i] è un oggetto di tipo Personne. Per visualizzarlo viene utilizzato il metodo __toString.

5.8. Creazione di una classe derivata dalla classe Persona (exemple_21)


<?php

class Personne {

// attributi della classe
  private $prénom;
  private $nom;
  private $âge;
  
// getter e setter
  public function getPrénom() {
    return $this->prénom;
  }
...

// costruttore
  function __construct($prénom, $nom, $âge) {
    // si utilizzano i set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // metodo
  public function initWithPersonne($p) {
    // inizializza l'oggetto corrente con una persona $p
    $this->__construct($p->prénom, $p->nom, $p->âge);
  }

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

}

// una classe derivata da Persona
class Enseignant extends Personne {

  // attributi
  private $discipline;   // materia insegnata

  // getter e setter

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

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

  // costruttore

  public function __construct($prénom, $nom, $âge, $discipline) {
    // attributi del genitore
    parent::__construct($prénom, $nom, $âge);
    // altri attributi
    $this->setDiscipline($discipline);
  }

  // sovraccarico della funzione __toString della classe padre
  public function __toString() {
    return "[" . parent::__toString() . ",$this->discipline]";
  }

}

// test
// creazione di una tabella di oggetti "Persona" e derivati
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70));

// identità di queste persone
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// fine
exit;
?>

Risultati:

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

Commenti

  • righe 3-35: la classe Personne
  • riga 38: la classe Enseignant deriva (estende) dalla classe Personne. La classe derivata Enseignant eredita gli attributi e i metodi dalla sua classe madre.
  • riga 41: la classe Enseignant aggiunge un nuovo attributo, discipline, che le è proprio
  • riga 55: il costruttore della classe Enseignant riceve 4 parametri
    • 3 per inizializzare la sua classe padre (nome, cognome, età)
    • 1 per la propria inizializzazione (materia)
  • riga 57: la classe derivata ha accesso ai metodi e ai costruttori della sua classe padre tramite la parola chiave parent ::. Qui si passano i parametri (nome, cognome, età) al costruttore della classe padre.
  • riga 64: il metodo __toString della classe derivata utilizza il metodo __toString della classe padre.
  • riga 71: un array contenente un oggetto Enseignant e un oggetto Personne.
  • riga 74: si esegue un ciclo sugli elementi dell'array
  • riga 75: verrà chiamato il metodo __toString di ciascun elemento $groupe[$i]. La classe Personne ha un metodo __toString. La classe Enseignant ne ha due: quella della sua classe padre e la propria. Ci si potrebbe chiedere quale verrà chiamata. L'esecuzione mostra che è stata chiamata quella della classe Enseignant. Funziona sempre così: quando viene chiamato un metodo su un oggetto, lo si cerca nel seguente ordine: nell’oggetto stesso, nella sua classe padre se ne ha una, poi nella classe padre della classe padre, ecc… La ricerca si interrompe non appena il metodo viene trovato.

5.9. Creazione di una seconda classe derivata dalla classe Personne (exemple_22)

L’esempio seguente crea una classe Etudiant derivata dalla classe Personne:


<?php

class Personne {

// attributi della classe
  private $prénom;
  private $nom;
  private $âge;

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

// costruttore
  function __construct($prénom, $nom, $âge) {
    // si passa tramite i set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // metodo
  public function initWithPersonne($p) {
    // inizializza l'oggetto corrente con una persona $p
    ...
  }

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

}

// una classe derivata da persona
class Enseignant extends Personne {

  // attributi
  private $discipline;   // materia insegnata

  // getter e setter
...

  // costruttore

  public function __construct($prénom, $nom, $âge, $discipline) {
    // attributi del genitore
    parent::__construct($prénom, $nom, $âge);
    // altri attributi
    $this->setDiscipline($discipline);
  }

  // sovraccarico della funzione _identité__toString della classe padre
  public function __toString() {
    return "[" . parent::__toString() . ",$this->discipline]";
  }

}

// una classe derivata da Persona
class Etudiant extends Personne {

  // attributi
  private $formation;   // materia insegnata

  // getter e setter

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

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

  // costruttore

  public function __construct($prénom, $nom, $âge, $formation) {
    // attributi del genitore
    parent::__construct($prénom, $nom, $âge);
    // altri attributi
    $this->setFormation($formation);
  }

  // sovraccarico della funzione __toString della classe padre
  public function __toString() {
    return "[" . parent::__toString() . ",$this->formation]";
  }

}

// test
// creazione di un array di oggetti "persona" e derivati
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70), new Etudiant("Steve", "Boer", 23, "iup2 qualité"));

// identità di queste persone
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// fine
exit;
?>

Risultati:

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

5.10. Le interfacce (exemple_23)

Un'interfaccia è una struttura che definisce i prototipi dei metodi. Una classe che implementa un'interfaccia definisce il codice di tutti i metodi dell'interfaccia.


<?php

// un'interfaccia
interface IExemple {
  function ajouter($i, $j);

  function soustraire($i, $j);
}

// implementazione 1 dell'interfaccia
class Classe1 implements IExemple {

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

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

}

// implementazione 2 dell'interfaccia
class Classe2 implements IExemple {

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

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

}

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

// ------------------- main
// creazione di 2 oggetti di tipo Classe1 e Classe2
$c1 = new Classe1();
$c2 = new Classe2();
// chiamata della funzione calcolare
calculer(4, 3, $c1);
calculer(14, 13, $c2);
?>

Risultati

17
21
127
201

Commenti

  • righe 4-8: l'interfaccia IExemple definisce due metodi: la funzione ajouter (riga 5) e la funzione soustraire (riga 7). L'interfaccia non definisce il codice di questi metodi. Saranno le classi che implementano l'interfaccia a farlo.
  • riga 11: la classe Classe1 implementa l'interfaccia IExemple. Definisce quindi un codice per i metodi ajouter (riga 13) e soustraire (riga 17).
  • righe 24-34: lo stesso vale per la classe Classe2
  • riga 37: il metodo calculer accetta tre parametri: due numeri interi $a e $b e un oggetto $interface che implementa l'interfaccia IExemple. Si sarebbe potuto scrivere function calculer($a,$b,$interface) senza specificare il tipo IExemple del parametro $interface. Indicandolo, si consente all’interprete PHP di verificare che il parametro effettivo sia effettivamente un oggetto che implementa l’interfaccia IExemple.
  • righe 38-39: utilizzo dei metodi ajouter e soustraire dell'oggetto $interface. Poiché quest’ultimo implementa l’interfaccia IExemple, sappiamo che possiede questi due metodi.
  • righe 44-45: creazione di due oggetti di tipi diversi ma che implementano entrambi l'interfaccia IExemple.
  • riga 47: si passa alla funzione calculer, passando l’oggetto $c1 di tipo Classe1 che implementa l’interfaccia IExemple.
  • riga 48: si passa alla funzione calculer, l'oggetto $c2 di tipo Classe2 che implementa l'interfaccia IExemple.