login  Naam:   Wachtwoord: 
Registreer je!
 Tutorials

Tutorials > PHP


Gegevens:
Geschreven door:
Joost
Moeilijkheidsgraad:
Normaal
Hits:
34266
Punten:
Aantal punten:
 (4.93)
Aantal stemmen:
14
Stem:
Niet ingelogd
Nota's:
 Lees de nota's (8)
 



Tutorial:

[OOP] Een begin maken met OOP

Inhoudsopgave:

1. Voorwoord.
2. Object Oriented Programming: de praktische theorie.
3. Object Oriented Programming: de technische theorie.
    3.1 Klassen en Objecten.
    3.2 Eigenschappen: methodes, attributen en constanten.
    3.3 Overerving.
    3.4 Polymorfisme.
    3.5 Inkapseling.
    3.5 Abstractie.
4. Je eerste klasse.
    4.1 Een klasse definiëren.
    4.2 Een methode toevoegen.
    4.3 Een object instantiëren.
    4.4 Een attribuut definiëren.
    4.5 $this
5. Toegang tot variabelen en methodes.
    5.1 Private, Protected en Public.
    5.2 __set()
    5.3 __get()
6. Constructor en destructor.
    6.1 __construct()
    6.2 __destruct()
7. Nawoord.

1. Voorwoord

Welkom bij deze tutorial over OOP, oftewel, Object Oriented Programming.

OOP is een programmeertechniek die voor het eerst in PHP verscheen bij versie 3. In PHP3 werd echter alleen het essentiële ondersteunt. PHP4 bood al behoorlijk wat verbeteringen, maar pas sinds PHP5 kunnen we pas echt spreken van OOP in PHP. Het is bij deze tutorial ook vereist om PHP5 te hebben. De code zal helaas niet werken in PHP4. De reden waarvoor ik hiervoor heb gekozen is de matige OO ondersteuning in PHP4, waardoor we om de faciliteiten die PHP5 biedt moeten gaan werken.

In deze tutorial zal de grondslag niet zo zeer liggen op het schrijven van ingewikkelde OO code. Ik ga je uitleggen wat OO is. Allereerst zullen we OO met de praktijk vergelijken. Hiermee hoop ik je een beeld te geven van de voordelen die OOP biedt. Daarna zal ik ingaan op de technische theorie van OOP. Welke begrippen hebben we, hoe zijn die gerelateerd tot elkaar enzovoorts. Op het einde gaan we onze eerste OO code programmeren, en gaan we in op enkele OOP methodieken.

We zullen in deze tutorial proberen zoveel mogelijk het object Auto te gebruiken. Dit is een duidelijk voorbeeld hoe OOP nou werkelijk in elkaar zit, zonder je tegelijk met een ingewikkelde applicatie te maken krijgt.

Het is niet vereist, maar wel gewenst dat je het procedurele programmeren onder de knie hebt. bij PP werk je van gebeurtenis tot gebeurtenis. Als er dit gebeurt, doet de code dit, en als er dat gebeurt, doet de code dat. OOP vergt een heel andere denkwijze: Welke objecten ga ik nodig hebben, wat moet het kunnen en wat zijn de eigenschappen? De stap naar OOP is voor sommigen erg lastig. Ze zien een klasse als een hoop gebundelde functies, en snappen de kracht van OO niet. Ik probeer je deze stap te laten begrijpen en je te onderwijzen in de denkwijze van OO programmeren. Na een tijdje zul je dan ook door gaan krijgen wat de kracht ervan is, wanneer je met OO hebt geëxperimenteerd. PHP kan je helaas geen theorethische denkfouten melden, hierin zul je jezelf moeten trainen.


2. Object Oriented Programming: de praktische theorie.

In de applicaties die je hebt ontwikkelt heb je vast geprobeerd structuur aan te brengen in je PHP code. Je hebt je bestanden waarschijnlijk gegroepeerd in in een bepaalde structuur, bijvoorbeeld een map images voor je afbeeldingen en een map includes voor je scripts die je include. Waarschijnlijk gebruik je ook functies voor acties die je meerdere keren moest doen.

Neem in je hoofd een voorbeeld van een Volkswagen Polo, een Ferrari en een Ford Excursion. Je ziet in een opslag dat het allemaal auto's zijn. Ongetwijfeld heb je niet gedacht aan een verzameling van schroeven, ramen en wielen. De eigenschap van de hersenen om voorwerpen te groeperen en verzamelingen als een voorwerp te zien, gebruiken we ook bij het OOP programmeren.

Stel, we moeten een routeplanner programmeren. We gebruiken verschillende vervoersmiddelen, waar we de route vanaf laten hangen. We introduceren het object auto in onze applicatie. Deze auto heeft eigenschappen die van belang zijn in onze applicatie: snelheid, actieradius enzovoorts. Onze routeplanner hoeft niet te weten hoe de motor is gemaakt. Ook is het niet van belang hoeveel zwaar de auto is. Daarintegen, wanneer we een programma moesten schrijven voor een automonteur, had dat wel van belang geweest. Bij OOP werken we objecten alleen uit tot het detailniveau dat we nodig hebben. Dit zorgt voor extra overzicht en besparen we ons de last van erg veel details.

Een ander belangrijk punt bij OOP is de mogelijkheid de code aan te passen zonder dat de rest van de applicatie moet worden aangepast. Stel, jij hebt thuis een mooie computer staan. Leuke randapparatuur erbij, een mooie grote monitor. Je besluit dat je een nieuwe, betere computer wilt hebben om te gamen. Je hoeft dan niet je monitor en boxjes en dergelijke te vervangen, maar alleen je computer. Dit kan, omdat een computer als losse module bestaat en wordt verkocht. De interne werking van je computer kan totaal anders zijn ( Quad core processor ten opzichte van een Pentium IV ) en toch hoef je niks aan te passen. Deze onderhoudbaarheid is een belangrijk kenmerk van OOP.

Een ander belangrijk kenmerk van OOP is de herbruikbaarheid van de code. Wanneer je een klasse hebt geschreven voor een applicatie, kan je deze moeiteloos hergebruiken in een andere applicatie. Het voordeel hiervan moge duidelijk zijn.

Hiermee hebben we 3 grote voordelen van OOP gehad:

Leesbaarheid
Door de modulaire opbouw is het eenvoudig het overizcht te bewaren.

Onderhoudbaarheid
Vanwege de duidelijke structuur kan je gemakkelijker het systeem aanpassen.
Vanwege de modulaire opbouw hoef je niet telkens het hele systeem om te gooien.

Herbruikbaarheid
Door de modulaire opzet kan je gemakkelijk code hergebruiken in een volgend project.
Na een tijdje zul je merken dat je een paar modules hebt die je in veel applicaties gebruikt.


3. Object Oriented Programming: de technische theorie.

De 2 belangrijkste begrippen van OOP zijn klasse en object. Een object is een instantie van een van een klasse. In ons auto voorbeeld kan je een klasse zien als het ontwerp van een auto en een object als de bouw ervan. Er kunnen dus meerdere objecten van één klasse worden gemaakt. Immers kunnen er ook meerdere auto's van één ontwerp worden gemaakt.

Een klasse bestaat uit eigenschappen. Dit is een verzameling voor methodes, attributen en constanten.
  • Een methode is een capaciteit van een klasse. Het is te vergelijken met een functie. Een auto kan bijvoorbeeld rijden of remmen.
  • Een attribuut (of member, of lid) is een variabele van een klasse. Deze is niet gewoon vanaf buiten de klasse ten benaderen, dit moet via de klasse zelf. Bij een auto is dit bijvoorbeeld de kleur.
  • Een constante is een constante van een klasse. Deze is, netzoals een attribuut, niet zonder de klasse zelf te benaderen.

Een ander begrip is inheritance, oftewel overerving.
Een klasse kan een andere klasse uitbreiden, met vaak een specialisatie. De nieuwe klasse erft dan sommige eigenschappen van de SuperClass, de klasse die hij uitbreidt. De simpelste vorm van overerving is Single Inheritance, oftewel Enkele Overerving. De klasse, bijvoorbeeld Ferrari, die een uitbreiding is op onze Auto klasse, is een voorbeeld van Single Inheritance. Wanneer we onze Ferrari klasse nog verder willen uitbreiden naar verschillende types, spreken we van Multiple Inheritance. We kunnen onze klasse Ferrari bijvoorbeeld uitbreiden in een klasse FerrariF430 en een klasse FerrariScaglietti. Deze twee klassen zullen dan nog steeds eigenschappen hebben van de SuperClass auto, maar ook de specialisatie van de Ferrari klasse.

Wanneer we een klasse laten overerven van een andere klasse, heb je al gauw nodig dat een bepaalde methode zich iets anders gedraagt. Je kan nieuwe methodes en attributen toevoegen, maar wat wanneer je een bepaalde methode iets wilt wijzigen? Het is verkeerd om de SuperClass te veranderen, omdat hier immers meerdere klassen van kunnnen erven en hij al naar behoren werkt. Daar is in OOP een begrip voor: polymorfisme. Met polymorfisme kan je bepaalde methodes opheffen en ze voor de nieuwe klasse specifiek aanpassen.

Gerelateerd aan overerving hebben we het begrip encapsulation, oftewel inkapseling.
Een ander woord voor inkapseling is Information Hiding. Een auto kan bijvoorbeeld remmen en gas geven. De bestuurder van de auto kan dit allemaal doen zonder te weten hoe de auto het precies doet. Encapsulation kan je definiëren als het afscheiden en het verbergen van hoe iets gebeurt. Een goed ontworpen object kan doen wat je wilt zonder dat je ooit weet hoe het gebeurt. Inkapseling wordt bereikt door het zichtbaarheid of toegangsbeheer. Hiermee specificeer je hoe toegankelijk eigenschappen van klassen zijn,

Aan de modulariteit die we in de vorige paragraaf hebben behandeld kun je het begrip abstractie plakken. Een klasse moet breed zijn. Dit is een fout die door beginnende OOP'ers weleens fout wordt gedaan. In plaats van het ontwerpen van een klasse die een Ferrari is, maak je een klasse Auto die acties voor elk soort auto bevat. Via overerving kan je dan een specifieke klasse maken voor een Ferrari. Deze klasse is op bepaalde punten gespecialiseerd voor een Ferrari.


Zo, dit was een hele hap aan theorie. Het geeft niet (ik verwacht het zelfs niet) als je het niet helemaal begrijpt, maar mettertijd zul je de begrippen leren kennen. Laat deze theorie op je bezinken. Lees het nog eens rustig over. Let er wel op, we gaan niet al deze theorie gebruiken in deze tutorial. Daar zijn eventuele vervolgtutorials voor, dit is simpelweg teveel voor een tutorial, en dat zou het ook te ingewikkeld maken. De tutorial is deels bedoelt om jullie een goed beeld te geven van OOP. Wees echter gerust, er is nog veel meer OOP theorie dan wat we nu hebben behandelt. Dit zijn veel basisprincipes van het OOP, meer hebben we voorlopig niet nodig. Laten we nu, eindelijk zul je denken, beginnen met onze OO code.


4. Je eerste klasse.

Laten we beginnen met het definiëren van onze auto klasse:

<?php

class Auto {
    
}

Een klassenaam wordt voorafgegaan door het keyword class.
De naamgeving van een klasse mag volledig naar je eigen inzicht zijn. Je mag alleen geen keywords gebruiken, en voor de rest gelden de regels die ook bij variabelen gelden.

We voegen een methode toe aan onze klasse:

<?php

class Auto {
    
    public function 
rijden( ){
        return 
"De auto rijdt!";
    }
    

Een methode wordt voorafgegaan door het keyword function.
In het voorbeeld staat er ook public voor. Dit zegt je nu nog niks, dat komt later. Tot die tijd is het het beste public te gebruiken. Een methode heeft dezelfde syntax als een gewone functie. Je kan parameters meegegeven, retourneren wat enzovoorts.

We gaan nu een object van de klasse maken, en de methode die we hebben geschreven uitvoeren:

<?php

class Auto {
    
    public function 
rijden(){
        return 
"De auto rijdt!";
    }
    


$oAuto = new Auto;
echo $oAuto->rijden(); 

We instantiëren eerst het object $oAuto van de klasse Auto. Hierbij gebruiken we het keyword new, gevolgd door de klassenaam.
Vervolgens roepen we via het net aangemaakt object de methode rijden aan. De syntax hiervoor is:

object->methodenaam();

Deze code zal "De auto rijdt!" op het scherm echo'en.

We gaan onze klasse iets uitbreiden met een attribuut, namelijk de kleur van de auto. Ook voegen we een methode toe met een parameter, en passen we de methode rijden wat aan:

<?php

class Auto {
    
    public 
$sKleur "";
    
    public function 
rijden( ){
        return 
"De auto, die " $this->getKleur( ) . " is, rijdt!";
    }

    public function 
setKleur$sKleur ){
        
$this->sKleur $sKleur;
        return;
    }
    
    public function 
getKleur( ){
        return 
$this->sKleur;
    }
    


$oAuto = new Auto;
$oAuto->setKleur"groen" );
echo $oAuto->rijden( ); 

We definiëren eerst het attribuut sKleur. Ook hier gebruiken we weer public, en geldt hetzelfde verhaal als bij methodes, daar komt later nog. Daarnaast is de methode setKleur toegevoegd, met de parameter $sKleur. Vervolgens gebruiken we $this om het attribuut de waarde van $sKleur te geven.

$this is een speciale variabele binnen OOP in PHP. Binnen een methode kun je verwijzen naar de instantie van de klasse m.b.v. $this. Je kan verwijzen naar een attribuut met $this->attribuutNaam; en naar een methode met $this->methodeNaam();.

De functie setKleur noemen we ook wel een setter. Hij set immers een waarde. Zoals je wel verwacht, de methode getKleur noemen we een getter. Deze retourneert een waarde van een attribuut. We zullen later nog iets dieper ingaan op op setters en getters.

We hebben de methode rijden zo aangepast dat hij nu ook de kleur van de auto weergeeft. Deze code zal de volgende output hebben: "De auto, die groen is, rijdt!".


Zo, we hebben onze eerste klasse al geschreven. We kennen de syntax van een klasse en een object, we weten hoe we attributen en methodes moeten definiëren en we kennen $this. In de volgende paragraaf gaan we een in op toegang tot variabelen en methodes, waarin het duidelijk wordt waarvoor public nou dient.

pijl top
5. Toegang tot variabelen en methodes.

Sinds PHP5 is er de mogelijkheid gekomen methodes en attributen 'fysiek' te verbergen. Dit is een sterk middel om beter te programmeren volgens de OO methodiek. Net als in vele andere OO talen kent PHP drie vormen van afscherming:
  • Private:
    Een methode/attribuut die met het keyword private is gedefinieerd kan alleen maar worden gebruikt binnen de klasse waarin hij is gedefinieerd.
  • Protected:
    Een methode/attribuut die met het keyword protected is gedefinieerd kent dezelfde eigenschappen als private, alleen zijn attributen/methodes ook nog beschikbaar in eventuele afgeleide klassen, via overerving.
  • Public:
    Een methode/attribuut die met het keyword public is gedefinieerd kan vanaf overal worden benaderd, ook vanaf buiten de klasse.
Een simpel schema van private, protected en public:

Public

Protected

Private

Eigen Klasse

Eigen Klasse en afgeleide klassen.

Alle PHP code.

Een uitgebreide uitleg hiervan is te vinden in de volgende tutorial: OOP_(Public,_Protected_en_Private). Waarschijnlijk is het niveau van die tutorial net wat te hoog (wordt al gewerkt met overerving), daarom besteed ik er ook nog wat aandacht aan. We gaan in deze paragraaf in op de toepassing ervan. In deze tutorial is het verschil tussen protected en private nog niet van belang, omdat we nog niet ingaan op overerving.


Stel, we hebben de volgende klasse:

<?php

class Auto {

    public 
$sKleur "";


Wanneer we een object zouden instantiëren en sKleur proberen te veranderen via de volgende code:

$oAuto = new Auto;
$oAuto->sKleur "groen"

werkt dat gewoon, evenals het opvragen. Deze code werkt echter ook:

$oAuto = new Auto;
$oAuto->sKleur -10

En dat is niet wat we willen. Hierdoor kan de werking van een object volledig foutlopen. Het zou het mooiste zijn als we konden forceren dat een attribuut altijd een correcte waarde bevat. Dan hoeven we maar één keer een check (bij het setten) uit te voeren of de waarde correct is.

Wanneer we het keyword public vervangen door het keyword private, en we proberen een van bovenstaande codes uit, zal de volgende error optreden:

Fatal error: Cannot access private property Auto::$sKleur in ...

Hierdoor is ons probleem van foute waardes invoeren al opgelost, maar nu moeten we nog wel een methode vinden om toch sKleur te veranderen. Je voelt hem al aankomen, dit doen we via een setter:

<?php

class Auto {
    
    private 
$sKleur "";

    public function 
setKleur$sKleur ){
        
$aValideKleuren = array('groen''rood''blauw''paars''geel''wit''zwart');    
        if( !
in_arraystrtolower$sKleur ), $aValideKleuren ) ){
           die( 
"Kleur niet bekend: " $sKleur );
        }
        
$this->sKleur $sKleur;
        return;
    }
    
}  

Nu bestaat er geen kans meer dat er vreemde waardes in het attribuut sKleur komen.
Wanneer we nu sKleur vanbuiten de klasse willen aanroepen, krijgen we ook een error. Daarvoor gebruiken we de getter uit de vorige paragraaf, getKleur(). Let wel op, je kan sKleur nog wel vanuit de klasse zelf aanroepen i.c.m. $this. Dan hoef je niet per sé de getter aan te roepen.


Speciaal voor setters en getters heeft PHP 2 speciale methodes: __set en __get. Deze functies worden aangeroepen wanneer jij via de gewone syntax een een attribuut probeert te veranderen / op te vragen. __set kent 2 parameters: de attribuutnaam en de value. __get kent één parameter: de attribuutnaam.

We hebben in onderstaande klasse een __set en een __get methode gedefinieerd:

<?php 

class Auto 
     
    private 
$sKleur ""
    
    public function 
__set$sAttribuut$sValue ){
        switch( 
$sAttribuut ){
            case 
'sKleur':
                
$aValideKleuren = array('groen''rood''blauw''paars''geel''wit''zwart');     
                if( !
in_arraystrtolower$sValue ), $aValideKleuren ) ){ 
                   die( 
"Kleur niet bekend: " $sValue ); 
                } 
                
$this->sKleur $sValue;
            break;
            default:
            break;
        }
        return;
    }
    
    public function 
__get$sAttribuut ){
        if( isset( 
$this->$sAttribuut ) ){
            return 
$this->$sAttribuut;
        }
        return 
false;
    }
     
}   

Wanneer we nu de volgende code uitvoeren:

$oAuto = new Auto;
$oAuto->sKleur = -1;

Zal dat op het scherm tonen: "Kleur niet bekend: -1".
Deze code zal nu ook geen error geven:

$oAuto = new Auto;
echo 
"De kleur van de auto is " $oAuto->sKleur;

Zal de kleur ook weergeven die je hebt ingesteld.

Het gebruik van __set en __get is erg gemakkelijk, maar ik vind het persoonlijk ook wel netjes met een setKleur bijvoorbeeld te werken. Ik vind het iets duidelijk, je krijgt er niet het idee bij dat de variabele public is. Dit is echter wel een beetje van je smaak afhankelijk, die keuze laat ik aan jezelf.


6. Constructor en destructor.

Twee bekende methodes in OOP zijn de contructor en de destructor. De definitie is eenvoudig:
De constructor wordt aangeroepen wanneer een object wordt geinstantieerd.
De destructor wordt aangeroepen wanneer een object wordt vernietigd via unset() of als het script klaar is.
De con- en destructor zijn, netzoals __set en __get, magische methodes in OOP PHP. Magische methodes beginnen in PHP altijd met twee underscores.

In de volgende klasse hebben we een constructor gedefinieerd:

<?php 

class Auto 
     
    private 
$sKleur ""

    public function 
__construct(){
        
$this->sKleur "groen";
        return;
    }
    
    public function 
rijden( ){ 
        return 
"De auto, die " $this->sKleur " is, rijdt!"
    } 
     
}  

Wanneer we nu een object instantiëren van Auto zal de constructor worden aangeroepen. Het attribuut sKleur krijgt dan direct een waarde. Wat we natuurlijk willen is dat de constructor een parameter krijgt met de kleur. Dat kan gewoon:

<?php  

class Auto {  
      
    private 
$sKleur "";  

    public function 
__construct$sKleur ){ 
        
$this->sKleur $sKleur
        return; 
    } 
     
    public function 
rijden( ){  
        return 
"De auto, die " $this->sKleur " is, rijdt!";  
    }  
      

Wanneer we nu een object willen instantiëren, geven we de parameters mee:

$oAuto = new Auto"groen" );
echo $oAuto->rijden();

Nu zal je auto de kleur groen meekrijgen, en die waarde in het attribuut sKleur stoppen. Wanneer je de checks nog wilt uitvoeren of de ingevoerde waarde wel geldig is, kan je de setter aanroepen via de constructor.
Dit kan met de volgende code, die je in de constructor moet zetten:

$this->setKleur$sKleur ); 
// of 
$this->__set'sKleur'$sKleur ); 

Welke je moet gebruiken hangt er vanaf of je een __set methode gebruikt, of setKleur.

Je zult jezelf nu misschien wel afvragen waarom we in deze code niet gewoon setKleur hebben gebruikt. Een terechte vraag, want ons voorbeeld is wat dat betreft ook nutteloos. Maar wanneer je bijvoorbeeld een methode verven hebt, die de auto pas een kleur geeft, kan je deze ook in je constructor aanroepen. Dan is het al een stuk effectiever. Dat voorbeeld is nog steeds een beetje vaag, maar als je bijvoorbeeld een praktische MySQL klasse gaat maken kan je je connectie naar de server maken in de constructor.

Zoals eerder gezegd, de destructor wordt aangeroepen wanneer het object wordt vernietigd. Dat kan op het einde van het script zijn maar ook via unset(). De methodenaam voor een destructor is __destruct. In de volgende code is een destructor toegevoegd:

<?php  

class Auto {  
      
    private 
$sKleur "";  

    public function 
__construct$sKleur ){ 
        
$this->sKleur $sKleur
        return; 
    } 
     
    public function 
rijden( ){  
        return 
"De auto, die " $this->sKleur " is, rijdt!";  
    }

    public function 
__destruct( ){
        echo 
"De auto is tegen een boom gereden en is nu total-loss!";
    }
      
}  

Wanneer we dan de volgende code uitvoeren:

$oAuto = new Auto"groen" );
echo $oAuto->rijden();
unset(
$oAuto);

Zal dat op het scherm printen:
De auto, die groen is, rijdt!
De auto is tegen een boom gereden en is nu total-loss!

Dit zal ook worden weergegeven als unset() niet wordt gebruikt, en het einde van het script is gekomen. De praktische toepassing van een destructor is bijvoorbeeld, in ons MySQL voorbeeld, het sluiten van de connectie naar de server.


7. Nawoord.

Gefeliciteerd, je hebt je eerste tutorial over OOP doorlopen! Het was een hele hap, ook omdat we een hoop theorie hebben behandeld. Het geeft niet als je nog niet alles begrijpt, laat het allemaal eens op je neerkomen en expirimenteer met wat je nu kan. Het is niet niks wat we hebben behandeld, je treft geen blaam als je het niet direct snapt. Dit zal mettertijd wel komen.

Vragen en opmerkingen kunnen via een reactie worden gegeven!

Joost


Referenties:
Larry Ullman: PHP5 voor gevorderden.
Arjan Burger en Wouter Tengeler: PHP5.
Wikipedia: Object-oriented programming.
Tri Pham/PHPFreakz: OOP Toepassen

« Vorige tutorial : Maak een Forum Volgende tutorial : OOP (Object Oriented Programming) »

© 2002-2019 Sitemasters.be - Regels - Laadtijd: 0.012s