9. Object Oriented PHP

Sinds versie 5 biedt PHP een goede ondersteuning voor OOP, Object Oriented Programming, het werken met classes.

9.1. De klassedefinitie

Een class definition begint met het woord "class" gevolgd door de klassenaam.
Eerst worden de eigenschappen vastgelegd: declaratie van de variabelen, met of zonder initialisatie.
Dan volgt de declaratie van de methods, eventueel met parameters en/of terugkeerwaarde.

Syntax:
class KlasseNaam {
  public $var1 = "een waarde";
  private $var2;

  public function functieNaam() {
    return $this->var1;
  }

  public function functieNaam($param) {
    $this->var2 = $param;
  }
}

Bij de creatie van een nieuwe instance van een class ken je het object toe aan een variabele:
$instance = new KlasseNaam();

9.2. Constructoren

Als je een nieuwe instantie van een klasse maakt, wordt de constructor aangeroepen.
Elke klasse bevat een impliciete constructor zonder parameters.

Natuurlijk kan je ook zelf een constructor met of zonder parameters voorzien en daarvoor kent PHP twee methoden:

Er mogen in PHP geen verschillende constructoren (met verschillende parameters) zijn.

Hieronder tweemaal dezelfde klassedefinitie:
<?php
class Persoon {
  var $naam;
  var $leeftijd;

  function Persoon($naam, $leeftijd) {
    $this->naam = $naam;
    $this->leeftijd = $leeftijd;
  }
}
?>

En met __construct
<?php
class Persoon {
  var $naam;
  var $leeftijd;

  function __construct($naam, $leeftijd) {
    $this->naam = $naam;
    $this->leeftijd = $leeftijd;
  }
}
?>

Om properties of methods uit een object aan te roepen gebruik je ->
$p = new Persoon('Hans', 25);
echo "<p>" .$p->naam . " is " . $p->leeftijd . " jaar</p>";

9.3. Overerving

Net zoals in Java kan je meer specifieke klassen afleiden van meer algemene.
Dat gebeurt met het sleutelwoord extends.

class Werknemer extends Persoon {
  var $loonschaal;

  function __construct($naam, $leeftijd, $loon) { //of function Werknemer
    $this->Persoon($naam, $leeftijd); //aanroep constructor superklasse
    $this->loonschaal = $loon;
  }
}

In PHP is alleen enkelvoudige overerving (single inheritance) mogelijk: een subklasse kan nooit van meer dan één superklasse erven.

9.4. Access Modifiers

Vanaf PHP5 is encapsulation mogelijk: het beperken van de toegankelijkheid van klassenvariabelen en -functies.

Er zijn drie soorten access modifiers (je vervangt ‘var’ door één van hen):

Zonder specificatie geldt standaard de toegankelijkheid public.

Als je toegankelijkeid 'private' gebruikt voor de variabelen van de klasse, dan zal je net zoals in Java getters en setters voorzien.

9.5. Static en niet-static

Standaard is een variabele van een klasse niet-static: elke instance van de klasse heeft een eigen waarde voor die variabele en de variabele kan enkel gebruikt worden als er inderdaad een instance van de klasse bestaat.

Je definieert een static variabele als volgt: static $varNaam = 0;

De eerste keer dat de klasse aangeroepen wordt, krijgt de variabele waarde nul en bij elke aanroep kan je bv. de waarde verhogen en dan heeft de variabele die hogere waarde in alle instances van de klasse.

De manieren om een static variabele aan te spreken zijn:

Als je een constante in een class definieert, is die automatisch public en static.
Er staat geen '$' voor de naam van de constante.
Definitie: const CONSTANTE = 'waarde van constante';

Gebruik:

Je kan ook een functie 'static' declareren en dan roep je ze aan met KlasseNaam::functie()

9.6. Polymorfie

Een subklasse die erft van een superklasse mag functies van de superklasse herdefiniëren (overriding), op voorwaarde uiteraard dat de functie dezelfde naam en parameters krijgt. Zodoende is ook polymorfie mogelijk.

Een voorbeeld (bestand vormen.php):
<?php
class Vorm {
  public function teken() {
    echo "<p>Teken een vorm</p>";
  }
}

class Rechthoek extends Vorm {
  public function teken() {
    echo "<p>Teken een rechthoek</p>";
  }
}

class Cirkel extends Vorm {
  public function teken() {
    echo "<p>Teken een cirkel</p>";
  }
}
?>

En dan kunnen we polymorfie toepassen (polymorfie.php):
<?php
require('vormen.php');
$vormen = array(new Rechthoek, new Rechthoek, new Cirkel, new Vorm);
foreach($vormen as $vorm) {
  $vorm->teken();
}
?>

9.7. Abstracte klasse

De klasse Vorm in het vorige voorbeeld kunnen we gewoon instantiëren, d.w.z. er instances van creëren met new Vorm().

Maar het is misschien beter als we er een abstracte superklasse van maken, een klasse die niet geïnstantieerd kan worden en met enkel de definities van functies – abstracte functies dus, die dan door elke subklasse ingevuld moeten worden.

Bijvoorbeeld:
abstract class Vorm {
 abstract public function teken();
}

9.8. Interfaces

Een interface kan je beschouwen als een abstracte klasse met daarin enkel abstracte methoden en constantes.
Via een interface wordt vastgelegd welke functionaliteit een klasse moet aanbieden.

Een klasse die een interface implementeert is verplicht om de abstracte methodes van de interface concreet uit te werken.

Een klasse kan één of meer interfaces implementeren via het keyword implements.

In tegenstelling tot klassen, is met interfaces wel meervoudige overerving mogelijk.

Een voorbeeld:
interface OppervlakteBerekenbaar {
  const PI = 3.1415927653;
  public function berekenOppervlak();
}

En dan kan een klasse de interface implementeren:
class Cirkel extends Vorm implements OppervlakteBerekenbaar {
  private $straal;

  public function __construct($r) {
    $this->straal = $r;
  }

  public function teken() {
    echo "<p>Teken een cirkel</p>";
  }

  public function berekenOppervlak() {
    return self::PI * pow($this->straal, 2);
  }
}

9.9. Type hinting

In PHP staat bij de parameters van een functie geen type-aanduiding, maar het mag wel.
Dan geef je een 'hint' over het type dat de functie verwacht – en als er een fout type doorgegeven wordt, stopt het programma met een foutmelding.

Bv. in een klasse Tekenblad:
function tekenVorm(Vorm $v) {
  $v->teken();
}