Skip to content

5. De objecten

5.1. Elke variabele kan een object met attributen worden (exemple_14)


<?php

// elke variabele kan per definitie attributen hebben
$obj1->attr1 = "un";
$obj1->attr2 = 100;
// geeft het object weer
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// wijzigt het object
$obj1->attr2+=100;
// geeft het object weer
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// wijst de waarde van object1 toe aan object2
$obj2 = $obj1;
// wijzigt obj2
$obj2->attr2 = 0;
// geeft beide objecten weer
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet2=[$obj2->attr1,$obj2->attr2]\n";
// wijst de referentie van object1 toe aan object3
$obj3 = &$obj1;
// wijzigt obj3
$obj3->attr2 = 10;
// geeft beide objecten weer
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet3=[$obj3->attr1,$obj3->attr2]\n";
// is een object een woordenboek?
print count($obj1)."\n";
while (list($attribut, $valeur) = each($obj1))
  print "obj1[$attribut]=$valeur\n";
// einde
exit;
?>

Resultaten:

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

Opmerkingen

  • regel 4: de notatie $obj->attr verwijst naar het attribuut attr van de variabele $obj. Als dit niet bestaat, wordt het aangemaakt, waardoor de variabele $obj een object met attributen wordt.
  • regel 13: de uitdrukking $obj2=$obj1 is, wanneer $obj1 een object is, een kopie van objecten via verwijzing. $obj2 en $obj1 zijn dus verwijzingen naar hetzelfde object. Het object zelf kan door beide verwijzingen worden gewijzigd.
  • regel 20: de uitdrukking $obj3=&$obj1 wijst aan $obj3 de verwijzing (het adres) van de variabele $obj1 toe. Als $obj1 een object is, zoals hier het geval is, is de voorgaande uitdrukking gelijk aan $obj3=$obj1.
  • regels 28-29: laten zien dat een object als een woordenboek kan worden doorlopen. De sleutels van het woordenboek zijn de namen van de attributen en de waarden van het woordenboek zijn de waarden van diezelfde attributen.
  • regel 27: de functie count kan op een object worden toegepast, maar geeft niet, zoals men zou verwachten, het aantal attributen weer. Een object vertoont dus overeenkomsten met een woordenboek, maar is er geen.

5.2. Een klasse Personne zonder gedeclareerde attributen (exemple_15)


<?php

class Personne {

  // attributen van de klasse
  // niet gedeclareerd – kunnen dynamisch worden aangemaakt
  
  // methode
  function identité() {
    // gebruikt a priori niet-bestaande attributen
    return "[$this->prénom,$this->nom,$this->âge]";
  }
}

// test
// de attributen zijn openbaar en kunnen dynamisch worden aangemaakt
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// aanroep van een methode
print "personne=" . $p->identité() . "\n";
// einde
exit;
?>

Resultaten:

personne=[Paul,Langevin,48]

Opmerkingen

  • regels 3-13: definiëren een klasse Personne. Een klasse is een mal op basis waarvan objecten worden aangemaakt. Een klasse is een verzameling van attributen en functies die methoden worden genoemd. Het is niet verplicht om de attributen te declareren.
  • regels 9-12: de methode identité geeft de waarde weer van drie attributen die niet in de klasse zijn gedeclareerd. Het sleutelwoord $this verwijst naar het object waarop de methode wordt toegepast.
  • regel 17: er wordt een object $p van het type Personne aangemaakt. Het sleutelwoord new wordt gebruikt om een nieuw object aan te maken. De bewerking retourneert een verwijzing naar het aangemaakte object (dus een adres). Er zijn verschillende schrijfwijzen mogelijk: new Personne(), new Personne, new personne. De naam van de klasse is hoofdlettergevoelig.
  • regels 18-20: de drie attributen die nodig zijn voor de methode identité worden aangemaakt in het object $p.
  • regel 22: de methode identité van de klasse Personne wordt toegepast op het object $p. In de code (regels 9-11) van de methode identité verwijst $this naar hetzelfde object als $p.

5.3. De klasse Persoon met gedeclareerde attributen (exemple_16)


<?php

class Personne {

  // klasseattributen
  var $prénom;
  var $nom;
  var $âge;

  // methode
  function identité() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }
}
// test
// de attributen zijn openbaar
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// aanroep van een methode
print "personne=" . $p->identité() . "\n";
// einde
exit;
?>

Resultaten:

personne=[Paul,Langevin,48]

Opmerkingen

  • regels 6-8: de attributen van de klasse worden expliciet gedeclareerd met het sleutelwoord var.

5.4. De klasse Personne met een constructor (exemple_17)

De voorgaande voorbeelden toonden exotische klassen zoals Personne, zoals die te vinden waren in PHP 4. Het wordt afgeraden om deze voorbeelden te volgen. We presenteren nu een Personne-klasse die voldoet aan de best practices van PHP 5:


<?php

class Personne {

// klasseattributen
  private $prénom;
  private $nom;
  private $âge;

// getters en 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;
  }

// constructor
  function __construct($prénom, $nom, $âge) {
    // we gaan via de set-methoden
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

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

}

// test
// aanmaken van een persoonobject
$p = new Personne("Paul", "Langevin", 48);
// identiteit van deze persoon
print "personne=$p\n";
// de leeftijd wijzigen
$p->setAge(14);
// identiteit van de persoon
print "personne=$p\n";
// einde
exit;
?>

Resultaten:

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

Opmerkingen

  • regels 3-48: de klasse Personne
  • regels 6-8: de privé-attributen (private) van de klasse. Deze attributen zijn alleen zichtbaar binnen de klasse. Andere bruikbare trefwoorden zijn:
  • public: maakt van het attribuut een openbaar attribuut dat zichtbaar is buiten de klasse
  • protected: maakt van het attribuut een beschermd attribuut dat zichtbaar is vanuit de klasse zelf en vanuit klassen die daarvan zijn afgeleid.
  • Omdat de attributen privé zijn, is er geen toegang toe van buiten de klasse. De volgende code kan dus niet worden geschreven:
$p=new Personne() ;
$p->nom="Landru" ;

Hier bevinden we ons buiten de klasse Personne. Aangezien het attribuut nom privé is, is regel 2 onjuist. Er zijn twee manieren om de privévelden van het object $p te initialiseren:

  • (vervolg)
    • gebruik maken van de openbare set- en get-methoden (de naam van deze methoden kan willekeurig zijn) uit de regels 11-33. We kunnen dan het volgende schrijven:
$p=new Personne() ;
$p->setNom("Landru") ;
  • (vervolg)
    • de constructor uit de regels 36-41 gebruiken. We schrijven dan:
$p=new Personne("Michel","Landru",44) ;

De bovenstaande code roept automatisch de methode van de klasse Personne op, genaamd __construct.

  • regel 54: deze regel geeft de persoon $p weer in de vorm van een tekenreeks. Hiervoor wordt de methode van de klasse Personne, genaamd __toString, gebruikt.

5.5. De klasse Personne met validatiecontrole in de constructor (exemple_18)

De constructor van een klasse is de juiste plaats om te controleren of de initialisatiewaarden van het object correct zijn. Maar een object kan ook worden geïnitialiseerd via de methoden set of gelijkwaardige methoden. Om te voorkomen dat dezelfde controles op twee verschillende plaatsen worden uitgevoerd, worden deze in de methoden set geplaatst. Als een initialisatiewaarde van een object onjuist blijkt te zijn, wordt er een uitzondering gegenereerd. Hier volgt een voorbeeld:


<?php

class Personne {

// attributen van de klasse
  private $prénom;
  private $nom;
  private $âge;
  
// getters en 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) {
    // de voornaam mag niet leeg zijn
    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) {
    // de achternaam mag niet leeg zijn
    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) {
    // de leeftijd moet geldig zijn
    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];
    }
  }

// constructor
  function __construct($prénom, $nom, $âge) {
    // we gebruiken de set-methoden
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

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

// test
// aanmaken van een Person-object
$p = new Personne("Paul", "Langevin", 48);
// identiteit van deze persoon
print "personne=$p\n";
// aanmaken van een foutief Person-object
try {
  $p = new Personne("xx", "yy", "zz");
} catch (Exception $e) {
  print $e->getMessage();
}
// einde
exit;
?>

Resultaten:

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

Opmerkingen

  • regels 23-30: initialisatie van het attribuut prénom en controle van de initialisatiewaarde
  • regel 25: gebruik van een reguliere expressie. De voornaam is een reeks van één of meerdere tekens, eventueel voorafgegaan of gevolgd door spaties.
  • regel 26: als de achternaam leeg is, wordt er een uitzondering gegenereerd; anders wordt de voornaam opgeslagen (regel 28)
  • regel 66: gebruik van de constructor van de klasse Personne
  • regel 68: gebruik van de methode __toString van de klasse Personne
  • regels 70-74: afhandeling van de eventuele uitzondering die wordt gegenereerd door de constructor van de klasse Personne.

5.6. Toevoeging van een methode die als tweede constructor fungeert (exemple_19)

In PHP 5 is het niet mogelijk om meerdere constructors met verschillende parameters te hebben waarmee een object op verschillende manieren kan worden geconstrueerd. Men kan dan methoden gebruiken die als constructor fungeren:


<?php

class Personne {

// attributen van de klasse
  private $prénom;
  private $nom;
  private $âge;
  
// getters en setters
  public function getPrénom() {
    return $this->prénom;
  }

….

// constructor
  function __construct($prénom, $nom, $âge) {
    // we gebruiken de set-methoden
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // methode
  public function initWithPersonne($p) {
    // initialiseert het huidige object met een persoon $p
    $this->__construct($p->prénom, $p->nom, $p->âge);
  }

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

}

// test
// aanmaken van een Person-object
$p = new Personne("Paul", "Langevin", 48);
// identiteit van deze persoon
print "personne=$p\n";
// aanmaken van een tweede persoon
$p2 = new Personne("Laure", "Adeline", 67);
// initialisatie van de eerste met de waarden van de tweede
$p->initWithPersonne($p2);
// controle
print "personne=$p\n";
// einde
exit;
?>

Resultaten:

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

Opmerkingen

  • regels 26-29: met de methode initWithPersonne kunnen de waarden van de attributen van een ander object (Personne) aan het huidige object worden toegewezen. Hier wordt gebruikgemaakt van de constructor __construct, maar dat is niet verplicht.

5.7. Een array van Personne-objecten (exemple_20)

Het volgende voorbeeld laat zien dat er arrays van objecten kunnen bestaan.


<?php

class Personne {

// attributen van de klasse
  private $prénom;
  private $nom;
  private $âge;
  
// getters en setters
  public function getPrénom() {
    return $this->prénom;
  }

...

// constructor
  function __construct($prénom, $nom, $âge) {
    // we gebruiken de set-methoden
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

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

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

}

// test
// aanmaken van een array met Person-objecten
$groupe = array(new Personne("Paul", "Langevin", 48), new Personne("Sylvie", "Lefur", 70));

// identiteit van deze personen
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// einde
exit;
?>

Resultaten:

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

Opmerkingen

  • regel 39: aanmaken van een tabel met 2 personen
  • regel 42: doorlopen van de tabel
  • regel 43: $groupe[$i] is een object van het type Personne. De methode __toString wordt gebruikt om het weer te geven.

5.8. Aanmaken van een klasse die is afgeleid van de klasse Persoon (exemple_21)


<?php

class Personne {

// attributen van de klasse
  private $prénom;
  private $nom;
  private $âge;
  
// getters en setters
  public function getPrénom() {
    return $this->prénom;
  }
...

// constructor
  function __construct($prénom, $nom, $âge) {
    // we gebruiken de set-methoden
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // methode
  public function initWithPersonne($p) {
    // initialiseert het huidige object met een persoon $p
    $this->__construct($p->prénom, $p->nom, $p->âge);
  }

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

}

// een klasse die is afgeleid van Persoon
class Enseignant extends Personne {

  // attributen
  private $discipline;   // onderwezen vak

  // getter en setter

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

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

  // constructor

  public function __construct($prénom, $nom, $âge, $discipline) {
    // bovenliggende attributen
    parent::__construct($prénom, $nom, $âge);
    // andere attributen
    $this->setDiscipline($discipline);
  }

  // overbelasting van de functie __toString van de bovenliggende klasse
  public function __toString() {
    return "[" . parent::__toString() . ",$this->discipline]";
  }

}

// test
// aanmaken van een tabel met Person-objecten en afgeleide objecten
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70));

// identiteit van deze personen
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// einde
exit;
?>

Resultaten:

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

Opmerkingen

  • regels 3-35: de klasse Personne
  • regel 38: de klasse Enseignant is afgeleid (extends) van de klasse Personne. De afgeleide klasse Enseignant erft de attributen en methoden van haar bovenliggende klasse.
  • regel 41: de klasse Enseignant voegt een nieuw, eigen attribuut toe: discipline
  • regel 55: de constructor van de klasse Enseignant ontvangt 4 parameters
    • 3 om de bovenliggende klasse te initialiseren (voornaam, achternaam, leeftijd)
    • 1 voor de eigen initialisatie (vak)
  • regel 57: de afgeleide klasse heeft toegang tot de methoden en constructors van de bovenliggende klasse via het sleutelwoord parent::. Hier worden de parameters (voornaam, achternaam, leeftijd) doorgegeven aan de constructor van de bovenliggende klasse.
  • regel 64: de methode __toString van de afgeleide klasse maakt gebruik van de methode __toString van de bovenliggende klasse.
  • regel 71: een array met een object Enseignant en een object Personne.
  • regel 74: er wordt een lus door de elementen van de array gelopen
  • regel 75: de methode __toString van elk element $groupe[$i] wordt aangeroepen. De klasse Personne heeft een methode __toString. De klasse Enseignant heeft er twee: die van de bovenliggende klasse en die van zichzelf. Je kunt je afvragen welke er wordt aangeroepen. Uit de uitvoering blijkt dat die van de klasse Enseignant is aangeroepen. Dit is altijd het geval: wanneer een methode op een object wordt aangeroepen, wordt er in de volgende volgorde naar gezocht: in het object zelf, in de bovenliggende klasse als die er is, vervolgens in de bovenliggende klasse van de bovenliggende klasse, enzovoort … De zoektocht stopt zodra de methode is gevonden.

5.9. Een tweede klasse aanmaken die is afgeleid van de klasse Personne (exemple_22)

In het volgende voorbeeld wordt een klasse Etudiant aangemaakt die is afgeleid van de klasse Personne:


<?php

class Personne {

// attributen van de klasse
  private $prénom;
  private $nom;
  private $âge;

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

// constructor
  function __construct($prénom, $nom, $âge) {
    // we gebruiken de set-methoden
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // methode
  public function initWithPersonne($p) {
    // initialiseert het huidige object met een persoon $p
    ...
  }

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

}

// een van de klasse ‘persoon’ afgeleide klasse
class Enseignant extends Personne {

  // attributen
  private $discipline;   // onderwezen vak

  // getter en setter
...

  // constructor

  public function __construct($prénom, $nom, $âge, $discipline) {
    // bovenliggende attributen
    parent::__construct($prénom, $nom, $âge);
    // andere attributen
    $this->setDiscipline($discipline);
  }

  // overbelasting van de functie _identité__toString van de bovenliggende klasse
  public function __toString() {
    return "[" . parent::__toString() . ",$this->discipline]";
  }

}

// een van de klasse Personne afgeleide klasse
class Etudiant extends Personne {

  // attributen
  private $formation;   // onderwezen vak

  // getter en setter

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

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

  // constructor

  public function __construct($prénom, $nom, $âge, $formation) {
    // bovenliggende attributen
    parent::__construct($prénom, $nom, $âge);
    // andere attributen
    $this->setFormation($formation);
  }

  // overbelasting van de functie __toString van de bovenliggende klasse
  public function __toString() {
    return "[" . parent::__toString() . ",$this->formation]";
  }

}

// test
// aanmaken van een array van persoon-objecten en afgeleide objecten
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70), new Etudiant("Steve", "Boer", 23, "iup2 qualité"));

// identiteit van deze personen
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// einde
exit;
?>

Resultaten:

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

5.10. Interfaces (exemple_23)

Een interface is een structuur die prototypen van methoden definieert. Een klasse die een interface implementeert, definieert de code van alle methoden van de interface.


<?php

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

  function soustraire($i, $j);
}

// implementatie 1 van de interface
class Classe1 implements IExemple {

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

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

}

// implementatie 2 van de interface
class Classe2 implements IExemple {

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

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

}

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

// ------------------- main
// aanmaken van 2 objecten van het type Klasse1 en Klasse2
$c1 = new Classe1();
$c2 = new Classe2();
// de functie berekenen aanroepen
calculer(4, 3, $c1);
calculer(14, 13, $c2);
?>

Resultaten

17
21
127
201

Opmerkingen

  • regels 4-8: de interface IExemple definieert twee methoden: de functie ajouter (regel 5) en de functie soustraire (regel 7). De interface definieert de code van deze methoden niet. Dit wordt gedaan door de klassen die de interface implementeren.
  • regel 11: de klasse Classe1 implementeert de interface IExemple. Ze definieert dus een code voor de methoden ajouter (regel 13) en soustraire (regel 17).
  • regels 24-34: hetzelfde geldt voor de klasse Classe2
  • regel 37: de methode calculer heeft drie parameters: twee gehele getallen $a en $b en een object $interface dat de interface IExemple implementeert. We hadden ook function calculer($a,$b,$interface) kunnen schrijven zonder het type IExemple van de parameter $interface te specificeren. Door dit wel aan te geven, kan de interpreter PHP controleren of de daadwerkelijke parameter inderdaad een object is dat de interface IExemple implementeert.
  • regels 38-39: gebruik van de methoden ajouter en soustraire van het object $interface. Omdat dit object de interface IExemple implementeert, weten we dat het over deze twee methoden beschikt.
  • regels 44-45: aanmaken van twee objecten van verschillende typen, maar die beide de interface IExemple implementeren.
  • regel 47: het object $c1 van het type Classe1, dat de interface IExemple implementeert, wordt doorgegeven aan de functie calculer.
  • regel 48: er wordt overgegaan naar de functie calculer, waarbij het object $c2 van het type Classe2 de interface IExemple implementeert.