PHP ยท Les 8 โ Laatste les
Klassen en namespaces
OOP-basis: klassen, constructor, visibility, inheritance en namespaces โ brug naar Symfony ยท 30 min
Klassen en objecten
Een klasse is een blauwdruk. Een object is een instantie van die blauwdruk.
<?php
// Klasse definitie
class Gebruiker {
// Properties (kenmerken)
public string $naam;
public string $email;
public int $leeftijd;
// Methoden (gedrag)
public function begroet(): string {
return "Hallo, ik ben {$this->naam}!";
}
public function isVolwassen(): bool {
return $this->leeftijd >= 18;
}
}
// Object aanmaken met new
$jan = new Gebruiker();
$jan->naam = "Jan de Vries";
$jan->email = "jan@example.com";
$jan->leeftijd = 20;
echo $jan->begroet(); // Hallo, ik ben Jan de Vries!
echo $jan->isVolwassen() ? "Volwassen\n" : "Minderjarig\n";
// Meerdere objecten van dezelfde klasse
$marie = new Gebruiker();
$marie->naam = "Marie Jansen";
$marie->leeftijd = 17;
echo $marie->isVolwassen() ? "Volwassen\n" : "Minderjarig\n";
โ ๏ธ Let op verschil met JS
De klasse-syntax lijkt sterk op JS (ES6+). Groot verschil: PHP gebruikt $this->property met een pijl (->), terwijl JS this.property met een punt gebruikt. En PHP properties hebben expliciet type-declaraties.
Constructor en property promotion
<?php
// Traditionele constructor
class Product {
public string $naam;
public float $prijs;
public int $voorraad;
public function __construct(string $naam, float $prijs, int $voorraad = 0) {
$this->naam = $naam;
$this->prijs = $prijs;
$this->voorraad = $voorraad;
}
public function getTotaalwaarde(): float {
return $this->prijs * $this->voorraad;
}
}
// Constructor property promotion (PHP 8) โ korter en cleaner
class ProductV2 {
public function __construct(
public readonly string $naam,
public float $prijs,
public int $voorraad = 0,
) {} // Body leeg โ alles staat in de parameters!
public function getTotaalwaarde(): float {
return $this->prijs * $this->voorraad;
}
}
$laptop = new ProductV2("Laptop", 899.99, 5);
echo $laptop->naam; // Laptop
echo $laptop->getTotaalwaarde(); // 4499.95
// readonly โ mag na aanmaken niet gewijzigd worden
// $laptop->naam = "Anders"; // Error!
๐ Komt terug in Symfony
Constructor property promotion gebruik je constant in Symfony-services: public function __construct(private readonly ProductRepository $repo) {}. Symfony injecteert automatisch de ProductRepository via dependency injection op basis van het type.
Visibility: public, private, protected
<?php
class BankRekening {
public string $rekeningNummer; // Overal leesbaar
private float $saldo; // Alleen binnen deze klasse
protected string $eigenaar; // Klasse + subklassen
public function __construct(string $nr, string $eigenaar, float $beginSaldo = 0) {
$this->rekeningNummer = $nr;
$this->eigenaar = $eigenaar;
$this->saldo = $beginSaldo;
}
// Getter โ gecontroleerde toegang tot private property
public function getSaldo(): float {
return $this->saldo;
}
// Setter โ validatie voor schrijven
public function storten(float $bedrag): void {
if ($bedrag <= 0) throw new \InvalidArgumentException("Bedrag moet positief zijn");
$this->saldo += $bedrag;
}
public function opnemen(float $bedrag): void {
if ($bedrag > $this->saldo) throw new \RuntimeException("Onvoldoende saldo");
$this->saldo -= $bedrag;
}
}
$rekening = new BankRekening("NL01TEST0001", "Jan", 100.00);
$rekening->storten(50);
echo $rekening->getSaldo(); // 150
// $rekening->saldo = 9999; // Fatal error โ private!
Overzicht visibility
public
Overal
protected
Klasse + children
private
Alleen de klasse zelf
โ ๏ธ Let op verschil met JS
In moderne JS gebruik je #saldo voor private properties (ES2022). In PHP heb je al tientallen jaren private. PHP's systeem is duidelijker en wordt in de hele Symfony-codebase gebruikt.
Inheritance (overerving)
<?php
// Basisklasse (parent)
class Dier {
public function __construct(
protected string $naam,
protected int $leeftijd,
) {}
public function beschrijving(): string {
return "{$this->naam} ({$this->leeftijd} jaar)";
}
public function geluid(): string {
return "...";
}
}
// Subklasse โ erft van Dier
class Hond extends Dier {
public function __construct(string $naam, int $leeftijd, private string $ras) {
parent::__construct($naam, $leeftijd); // Roep parent constructor aan
}
// Method override
public function geluid(): string {
return "Woef!";
}
public function beschrijving(): string {
return parent::beschrijving() . " โ {$this->ras}";
}
}
class Kat extends Dier {
public function geluid(): string { return "Miauw!"; }
}
$hond = new Hond("Rex", 3, "Labrador");
$kat = new Kat("Whiskers", 5);
echo $hond->beschrijving() . "\n"; // Rex (3 jaar) โ Labrador
echo $hond->geluid() . "\n"; // Woef!
echo $kat->geluid() . "\n"; // Miauw!
// instanceof controle
var_dump($hond instanceof Dier); // bool(true)
๐ Komt terug in Symfony
Symfony gebruikt inheritance overal: class ProductController extends AbstractController geeft je toegang tot render(), redirectToRoute(), etc. class ProductRepository extends ServiceEntityRepository geeft je Doctrine-query-methoden. Je schrijft alleen wat specifiek is voor jouw klasse.
Namespaces en autoloading
Namespaces voorkomen naamconflicten en organiseren grote projecten. PSR-4 autoloading via Composer zorgt dat klassen automatisch geladen worden.
<?php
// src/Entity/Product.php
namespace App\Entity;
class Product {
public function __construct(
private string $naam,
private float $prijs,
) {}
public function getNaam(): string { return $this->naam; }
}
// ---
// src/Service/PrijsCalculator.php
namespace App\Service;
use App\Entity\Product; // Importeer Product-klasse
use App\Repository\ProductRepository;
class PrijsCalculator {
public function __construct(
private readonly ProductRepository $repo
) {}
public function berekenKorting(Product $product, float $pct): float {
return $product->getPrijs() * (1 - $pct / 100);
}
}
// ---
// composer.json โ PSR-4 autoloading
// "autoload": { "psr-4": { "App\\": "src/" } }
// Composer vindt App\Entity\Product in src/Entity/Product.php
Namespace-regels in Symfony
โ namespace App\Controller; โ bestand in src/Controller/
โ namespace App\Entity; โ bestand in src/Entity/
โ namespace App\Service; โ bestand in src/Service/
โ use importeert klassen uit andere namespaces
๐ Komt terug in Symfony
Elke PHP-file in een Symfony-project begint met namespace App\.... Symfony's Dependency Injection Container weet welke services beschikbaar zijn door namespaces te scannen. Jij schrijft klassen in de juiste map en Symfony doet de rest.
Sandbox โ OOP in de praktijk
Bouw een kleine productcatalogus met klassen, inheritance en type hints.
// output
Klik op Uitvoeren...
Kennischeck
Wat je nu weet
PHP-track afronden
Markeer alle 8 lessen als voltooid en start de Symfony-track.