web2 logo

Object-oriented programming met PHP

Object-oriented programming met PHP

Bij het lezen van artikelen over PHP ben je vast de afkorting OOP wel eens tegengekomen. OOP is de afkorting van Object-Oriented progamming. Object-Oriented Programming is een programmeerstijl waarbij gegevens en functies worden georganisserd in objecten. Het principe "Don't Repeat Yourself" (DRY) speelt hierbij een belangrijke rol. Hierbij wordt de programmacode zodanig gemaakt dat er geen herhalingen van code optreden. Dit maakt de code effiënter en overzichtelijker. In OOP gebruiken we classes en objects. Een object is een instance (exemplaar) van een class. Een class kun je zien als een sjabloon en een object is iets wat gemaakt is op basis van dat sjabloon.

Class

Een class maak je met het keywoord class. De inhoud van de class zet je tussen gekrulde haken. Voorbeeld: <?php class Pagina { // hier de code ... } ?> Een class heeft properties en methods. Properties zijn variabelen en methods zijn functies. Voorbeeld: <?php class Pagina { // Properties public $titel; public $artikel; // Methods function titel_instellen($titel) { $this->title = $titel; } function titel_opvragen() { return $this->titel; } } ?> Vanaf PHP versie 7.4 mag je ook 'typed' properties gebruiken: <?php class Pagina { // Properties public string $titel; public string $artikel; } ?> Een 'typed' property geeft een error als deze wordt opgevraagd terwijl deze nog NULL is. Een object maken op basis van een class kan met het new keyword: $index = new Pagina(); $contact = new Pagina(); $index->titel_instellen('Welkom'); $contact->titel_instellen('Contactformulier'); // gegevens opvragen: echo $index->titel_opvragen(); echo $contact->titel_opvragen();

$this

Wat is $this? Het $this keyword verwijst naar het huidige object en is alleen beschikbaar binnen methods. Als je buiten de class rechtstreeks $titel wil aanpassen, dan moet je dat met de naam van het object doen: <?php class Pagina { public $titel; function wis_titel() { $this->titel = ''; } } $index = new Pagina(); $index->titel = "Welkom";

instanceof

Met instanceof kun je controleren of een object bij een bepaalde class hoort: $index = new Pagina(); var_dump($index instanceof Pagina);

Constructor

Een constructor is een functie die wordt uitgevoerd als je een object maakt van een class. In PHP heet deze speciale functie: __construct(). Deze naam begint met 2 underscores. Voorbeeld: <?php class Pagina { // Properties public $titel; public $artikel; // Methods function __construct($titel) { $this->title = $titel; } // deze functie wordt door de constructor overbodig: // function titel_instellen($titel) { // $this->title = $titel; // } function titel_opvragen() { return $this->titel; } } $index = new Pagina("Welkom"); echo $index->titel_opvragen(); ?> In bovenstaand voorbeeld wordt via de constructor slechts één property ingesteld, dat mogen er ook meer zijn. Als je meerdere properties via de constructor instelt, wordt de besparing in code groter: meerdere functies worden dan vervangen door de toewijzingen in de conctructor functie. Vanaf PHP versie 8.0 bestaat de mogelijkheid van contructor promotion, wat van de argumenten van de constructor meteen properties maakt, dit bespaart je extra code: <?php class Pagina { // Properties public $titel; public $artikel; // Door toevoeging van de access modifier 'private' // aan het argument wordt deze method compacter: function __construct(private $titel) { } function titel_opvragen() { return $this->titel; } } $index = new Pagina("Welkom"); echo $index->titel_opvragen(); ?> Meer over Constructors and Destructors.

Destructor

Een destructor is het omgekeerde van een constructor. Een destructor is een functie die wordt uitgevoerd als een object ophoudt te bestaan, bijvoorbeeld door het bereiken van het einde van het script. Ook een destructor heeft een speciale naam die begint met 2 underscores: __destruct(). <?php class Pagina { // Properties public $titel; public $artikel; // Methods function __construct($titel) { $this->title = $titel; } function __destruct() { echo "De titel van de pagina is {$this->titel}." } } $index = new Pagina("Welkom"); ?> Een destructor heeft nooit argumenten. Meer over Constructors and Destructors.

Access modifiers

Access Modifiers kun je gebruiken om in te stellen waar properties en methods gebruikt kunnen worden. Er zijn 3 access modifiers:

public
algemeen toegankelijk (default)
protected
toegankelijk binnen de class en in classes die zijn afgeleid van die class
private
alleen toegankelijk binnen de class

Voorbeeld: <?php class Pagina { public $url; protected $titel; private $artikel; } $index = new Pagina(); // dit gaat goed: $index->url = 'index.php'; // dit gaat fout, want 'protected' daarom niet bereikbaar buiten een class: $index->titel = 'Welkom'; // dit gaat fout, want 'private' daarom niet bereikbaar buiten de class $index->artikel = '<h1>Artikel 1</h1><p>In dit artikel...</p>'; ?> Een private property kan gebruikt worden om te voorkomen dat deze property rechtstreeks van buiten een class wordt aangesproken. De enige manier om deze properties aan te passen is via getter en setter methods van de class waarmee je extra controle hebt over welke aanpassingen zijn toegestaan. Meer over Visibility.

Inheritance

Inheritance is een term die in Object-Oriented Programming wordt gebruikt om aan te geven dat een class afgeleid is van een andere class. De class die 'erft' van een andere class krijgt de beschikking over alle public en protected properties en methods van de 'ouder' class. Een inherited class wordt aangegeven met het extends keyword. Voorbeeld: <?php class Pagina { public $url; public $titel; public function __construct($url,$titel) { $this->url = $url; $this->titel = $titel; } public function pagina_info() { echo "Dit is de pagina met url {$this->url} en de titel is {$this->titel}."; } } // Pagina_met_formulier erft van Pagina: class Pagina_met_formulier extends Pagina { public function formulier() { echo "<form>...</form>"; } } $contact = new Pagina_met_formulier("contact.php","Contactformulier"); $contact->pagina_info; $contact->formulier; ?> In het bovenstaande voorbeeld erft $contact via Pagina_met_formulier van Pagina. De properties '$url' en '$titel', alsmede de method 'pagina_info' zijn zodoende ook beschikbaar voor $contact. Daarnaast heeft $contact ook een eigen method: 'formulier'. Als 'Pagina' ook protected methods en properties zou hebben, dan erft $contact deze niet. Een protected method van 'Pagina' kan echter wel worden aangeroepen binnen de class 'Pagina_met_formulier'. Als je in een afgeleide class een method of property definiëerd die ook in de 'ouder' class voorkomt en die de afgeleide class geërfd heeft, dan vervang je daarmee de geërfde property of method in de afgeleide class. Je kunt dus een afgeleide class maken die niet alles erft van de 'ouder' class door properties en methods die je anders wil hebben te vervangen.

Met het keyword final kan je voorkomen dat van een class een afgeleide class wordt gemaakt of dat een method wordt vervangen in een afgeleide class. Voorbeeld met een final class: <?php final class Pagina { // ... code ... } // dit zal een foutmelding geven: class Pagina_met_formulier extends Pagina { // ... code ... } ?> Voorbeeld met een final method: <?php class Pagina { final public function pagina_info() { // ... code ... } } class Pagina_met_formulier extends Pagina { // dit zal een foutmelding geven: public function pagina_info() { // ... code ... } } ?> Meer over Object Inheritance.

Class constants

Je kunt in een class constanten definiëren. Constanten kun je niet meer veranderen nadat ze zijn gemaakt. Het keyword om een constante te maken is const. De namen van constanten zijn hoofdlettergevoelig en het is de gewoonte om constanten een naam te geven die geheel uit hoofdletters bestaat. Je vraagt een constante op via de scope resolution operator, dit is een dubbele dubbele punt. Voor de dubbele dubbele punt staat de naam van de class (als je de constante opvraagt buiten de class) of 'self' (als je de constante opvraagt binnen de class). Voorbeeld: <?php class Hallo { const TEKST = "hallo wereld!"; public function melding() { echo self::TEKST; } } echo Hallo::TEKST; $hoi = new Hallo(); $hoi->melding(); ?> Meer over Class Constants.

Abstract classes

Een abstract class is een class met op zijn minst één abstract method. Een abstract method is een method die pas in de afgeleide class volledig wordt gedefiniëerd. Een abstract method wordt gedefiniëerd met het abstract keyword. Van een abstract class kan geen object worden gemaakt, de abstract methods in een abstract class zijn nog niet gedefiniëerd en dus nog niet bruikbaar. Een class die wordt afgeleid van een abstract class via het extends keyword kan de abstract methods uit de 'ouder' class gebruiken door deze dezelfde naam te geven en nader te definiëren. De afgeleide method moet eenzelfde of minder beperkte access modifier hebben als de 'ouder' method. Het aantal verplichte argumenten moet ook gelijk zijn, maar de afgeleide mag extra optionele argumenten hebben. Voorbeeld: <?php // abstract class ('ouder') abstract class Pagina { public $titel; public function __construct($titel) { $this->titel = $titel; } // de abstract method 'omschrijving' moet in de // 'kind' class worden gedefiniëerd abstract public function omschrijving() : string; } // afgeleide class ('kind') // de constructor wordt geërfd van de abstract class // de functie 'omschrijving' wordt hier gedefiniëerd class Pagina_met_formulier extends Pagina { public function omschrijving() : string { return "Dit is een pagina met een formulier en de titel is $this->titel."; } } // een object maken van de 'kind' class $contact = new Pagina_met_formulier("Contact"); echo $contact->omschrijving(); echo "<br>"; ?> Meer over Class Abstraction.

Interfaces

Met interfaces kun je bepalen welke methods een class moet implementeren. Hiermee kun je afdwingen dat verschillende classes op dezelfde manier gebruikt worden. Wanneer meerdere classes dezelfde interface gebruiken spreken we van polymorphism. Een class die een interface implementeert wordt een concrete class genoemd. Interfaces lijken op abstract classes, de verschillen zijn:

  • Interfaces mogen geen properties hebben, abstract classes wel.
  • Interface methods mogen alleen public zijn, terwijl abstract methods ook protected mogen zijn.
  • Alle methods in een interface zijn automatisch abstract, het abstract keyword is hier niet nodig.
  • Classes kunnen een interface implementeren en tegelijk ook van een andere class erven.
Een interface gebruik je via het implements keyword. Voorbeeld: <?php // Interface maken interface Pagina { public function geef_omschrijving(); } // Class maken class Pagina_met_formulier implements Pagina { public function geef_omschrijving() { echo "<description>Pagina met formulier</description>"; } } // Object maken $contact = new Pagina_met_formulier(); $contact->geef_omschrijving(); ?> Meer over Object Interfaces.

Traits

In PHP kan een class slechts van één andere class erven. Als je toch meerdere eigenschappen wil laten erven, dan kun je traits gebruiken. Met traits kun je methods en abstract methods definiëren die in meerdere classes gebruikt kunnen worden. Deze methods mogen elke access modifier hebben (public, private of protected). Traits maak je met het trait keyword. Voorbeeld: <?php trait Navigatie { public function navbar() { echo "<nav>...</nav>"; } } trait Invul { public function formulier() { echo "<form>...</form>"; } } class Pagina { use Navigatie; } class Pagina_met_formulier { use Navigatie, Invul; } $index = new Pagina(); $index->navbar(); $contact = new Pagina_met_formulier(); $contact->navbar(); $contact->formulier(); ?> Als je meerdere traits gebruikt voor een class, dan kunnen er naamconflicten optreden als er traits zijn die methods hebben met dezelfde namen. Dit kun je oplossen door insteadof te gebruiken: <?php trait Artikel { public function titel() { //... } } trait Inhoud { public function titel() { // ... } } class Pagina ( use Artikel, Inhoud{ Artikel::titel insteadof Inhoud; } ) ?> Mocht je in het bovenstaande voorbeeld toch beide 'titel' methods willen gebruiken, dan kan je met het as keyword een alias instellen: class Pagina ( use Artikel, Inhoud{ Inhoud::titel as titelInhoud; Artikel::titel insteadof Inhoud; } ) $index = new Pagina(); $index->titel(); // volgens Artikel $index->titelInhoud(); // volgens Inhoud Meer over Traits.

Static methods

Een static method is een method die ook buiten een object om aan te roepen is. Een method die alleen binnen een object van een class aan te roepen is, wordt een instance method genoemd. Een static method wordt gemaakt met de keywords public static function en is algemeen beschikbaar. De static method wordt aangeroepen via de class naam gevolgd door een dubbele dubbele punt en dan de naam van de static method. Voorbeeld: <?php class Pagina { public static function domeinnaam() { return "web2.nl"; } public static function toon_domeinnaam() { echo "web2.nl<br>"; } // De static method binnen de class gebruiken public function __construct() { self::toon_domeinnaam(); } } // De static method buiten de class aanroepen Pagina::toon_domeinnaam(); // De static method in een andere class gebruiken class Pagina_met_formulier { public function webnaam() { Pagina::toon_domeinnaam(); } } // De static method in een afgeleide class gebruiken class Info_pagina extends Pagina { public $naamwebsite; public function __construct() { $this->naamwebsite = parent::domeinnaam(); } } $over_ons = new Info_pagina; echo $over_ons->naamwebsite; ?> Meer over Static Keyword.

Verschillen tussen self en $this

'self' vertegenwoordigt een class, '$this' vertegenwordigt een instantie van een class (object). 'self' begint niet met het dollarteken, '$this' begint wel met het dollarteken. 'self' wordt gevolgd door de :: operator, '$this' wordt gevolgd door de object operator ->. De naam van de eigenschap begint na de :: operator altijd met een dollarteken, na de object operator -> volgt geen dollarteken.

Static properties

Net als static methods, kunnen ook static properties aangeroepen worden buiten een object van een class om. Ook hier wordt het static keyword gebruikt en ook de dubbele dubbele punt wordt gebruikt zoals bij de static methods. Voorbeeld: <?php class Pagina { public static $domeinnaam = "web2.nl"; public function geef_domeinnaam() { return self::$domeinnaam; } } // zonder een obejct van de class te maken de property aanroepen echo Pagina::$domeinnaam; // object maken en functie aanroepen die een static property geeft $index = new Pagina(); echo $index->geef_domeinnaam(); // afgeleide class maken class Pagina_met_formulier extends Pagina { public function toon_domeinnaam() { return parent::$domeinnaam; } } // object van de afgeleide class maken $contact = new Pagina_met_formulier(); echo $contact->toon_domeinnaam(); ?> Meer over Static Keyword.

Namespaces

Met namespaces kun je PHP-projecten organiseren. Classes die bij elkaar horen kun je in dezelfde namespace plaatsen. Met namespaces kun je ook naamconflicten voorkomen. Dezelfde namen mogen gebruikt worden als ze zich in verschillende namespaces bevinden. Een namespace kun je vergelijken met een map in je bestandssysteem, bestanden mogen dezelfde naam hebben als ze in verschillende mappen staan. Door de naam van de map voor de naam van het bestand te plaatsen weet je welk bestand er bedoeld wordt. De namespace declaratie moet altijd aan het begin van een PHP-bestand staan: <?php namespace Html; class Navigatie { ... } ?> Een class gebruiken uit een andere namespace kan door deze vooraf te laten gaan door de naam van de namespace en een backslash: $navbar = new Html\Navigatie() Je kunt zowel een namespace als een class een alias geven om zo een kortere naam te kunnen gebruiken: # Alias voor een namespace: use Html as H; $navbar = new H\Navigatie(); # Alias voor een class: use Html\Navigatie as N; $navbar = new N(); Je kunt namespaces ook 'nesten': namespace Site\Html; Meer over Namespaces.

Classes zonder naam

Classes zonder naam zijn anonieme classes. Deze anonieme classes worden vaak gebruikt bij het testen van PHP scripts. Voorbeeld: <?php $mijnpagina = new class { public function geef_titel(string $tekst): void { echo '<title>' . $tekst . '</title>'; } } $mijnpagina->geef_titel('Dit is mijn pagina'); ?> Deze anonieme classses mogen ook interfaces implementeren met implements en erven van een andere class met extends. Meer over Anonymous classes.

Classes, interfaces en traits automatisch laden

Het is een goede gewoonte om elke PHP class, interface of trait in een eigen bestand op te slaan met de naam van de class, interface of trait als bestandsnaam. Deze bestanden kunnen dan ook nog in verschillende mappen georganiseerd zijn. Je laadt deze bestanden dan met een require, require once, include of include once opdracht. Om classes, interfaces en traits automatisch te laden kun je een functie maken die je automatisch laat aanroepen als een class, interface of trait nodig is. Dit automatisch aanroepen van je laadfunctie kan via de functie spl_autoload_register(). Voorbeeld van bestand functies.php: <?php function laad_mijn_class($class_naam) { $bestandspad = 'map_met_classes/' . $class_naam . '.php'; if (file_exists($bestandspad)){ require $bestandspad; } } spl_autoload_register('laad_mijn_class'); ?> Voorbeeld van index.php dat bovenstaand functies.php gebruikt om classes automatisch te laden als ze gebruikt worden zonder ze afzonderlijk aan te roepen: <?php require 'functions.php'; $mijn_object = new Mijn_class('info'); In het bovenstaande voorbeeld wordt de class 'Mijn_class' automatisch geladen uit de map 'map_met_classes' via de functie 'laad_mijn_class' die wordt aangeroepen door 'spl_autoload_register'. Je mag meer als één 'spl_autoload_register' functie gebruiken, je kunt dus voor elke map met classes, interfaces of traits een aparte functie gebruiken. Om de gezochte class, interface of trait te vinden worden deze functies dan allemaal afgelopen. Meer over Autoloading Classes.

naar boven

term zoeken