Inleiding object georienteerd programmeren (php5)
Note: This is a post that was created earlier and written in Dutch.
VOORKENNIS
Als voorkennis voor dit artikel dien je voldoende kennis te bezitten over:
* functies
* globale variabelen
* (typen) variabelen
WAT IS OBJECT GEORIENTEERD PROGRAMMEREN?
Om uit te kunnen leggen wat object georiënteerd programmeren is, wil ik het eerst hebben over de 2 voornaamste manieren van programmeren.
Deze 2 manieren zijn:
- Linear Programmeren
- Object Georiënteerd Programmeren
LINEAR PROGRAMMEREN
Linear programmeren is de manier van programmeren, waarmee eigenlijk de meeste mensen beginnen te programmeren. Hierbij wordt de code van boven naar beneden doorlopen waarbij er eventueel functies aangeroepen worden. Bij deze manier van programmeren staat de code centraal, daarom noemt men deze methode ook wel 'code centric'.
Voorbeeld 1.0 - Linear Programmeren
[php]< ?php
$sBestandsnaam = "tekstbestand.txt";
$aRegels = array();
$sOutput = "";
if(!file_exists($sBestandsnaam))
{
die("Bestand: ".$sBestandsnaam." bestaat niet!");
}
else
{
$aRegels = file($sBestandsnaam);
}
if (is_array($aRegels) && count($aRegels))
{
foreach ($aRegels as $sInhoud)
{
$sOutput .= $sInhoud;
}
}
print ($sOutput);
?>[/php]
OBJECT GEORIËNTEERD PROGRAMMEREN
Object Georiënteerd Programmeren ( vaak wel afgekort als OOP - Object Orientated Programming) is een manier van programmeren waarbij de data als centraal punt genomen wordt (men noemt dit 'data centric'). Object Georiënteerd Programmeren volgt daarnaast ook een andere aanpak dan linear, namelijk hierbij is het van belang dat men de code zo organiseert dat alle bijelkaar behorende data en functies bij elkaar geplaatst worden.
Voorbeeld 1.1 - Object Georiënteerd Programmeren
[php]< ?php
// tekstbestand.php
class tekstbestand
{
var $aRegels;
var $sOutput;
function tekstbestand()
{
$this->aRegels = array();
$this->sOutput = "";
}
function laadTekstBestand()
{
$sBestand = "tekstbestand.txt";
$aRegels = array();
if(!file_exists($sBestandsnaam))
{
die("Bestand: ".$sBestandsnaam." bestaat niet!");
}
else
{
$aRegels = file($sBestandsnaam);
}
}
function printTekstBestand()
{
$sOutput = "";
if (is_array($aRegels) && count($aRegels))
{
foreach ($aRegels as $sInhoud)
{
$sOutput .= $sInhoud;
}
}
print $sOutput;
}
}
$oTxt = new tekstbestand();
$oTxt -> laadTekstBestand();
$oTxt -> printTekstBestand();
?>[/php]
Zoals je kunt zien is voorbeeld 1.1 compleet anders dan voorbeeld 1.0. In voorbeeld 1.1 is alles in 1 klasse (classe) gestopt genaamd "tekstbestand", deze klasse (classe)bevat alle functies die er nodig zijn om een tekstbestand in te laden en daarna te printen. Verder op deze pagina vindt je meer informatie over klasses (classes).
Voor het gemak is voorbeeld 1.1 nog in PHP4 geschreven, daar de overgang anders naar mijn mening te snel gaat.
WAAROM OOP?
Okee, nu vraag je je vast af waarom juist OOP te programmeren i.p.v. het klassieke linear programmeren (ook wel procedureel programmeren genoemd).
Dat zal ik uitleggen aan de hand van 3 punten:
- leesbaarheid
- onderhoudbaar
- hergebruik
De code van een klasse die logisch bij elkaar hoort, staat ook fysiek bij elkaar.
Doordat de code van een klasse netjes gegroepeerd staat, is deze beter te onderhouden, dan wanneer je deze code ergens in een meters lang bestand moet opzoeken.
Wanneer je een classe goed maakt, is deze ook gemakkelijk weer te gebruiken voor andere projecten.
KLASSE (CLASS)
Wat is een klasse nou eigenlijk? Een klasse is een blauwdruk van een object, waarin de gegevens en functionaliteit van een worden beschreven.
Een klasse ziet er als volgt uit:
voorbeeld 1.2 -- een klasse (class)
[php]< ?php
class klassenaam
{
function klassenaam()
{
// code hier
}
}
?>[/php]
OBJECT EN KLASSE
Zoals ik eerder aangaf is een klasse een blauwdruk van een object. Een object is een instantiatie van een klasse, daarnaast is een object alleen actief wanneer de code uitgevoerd wordt. Omdat elk object een unieke identificatie heeft is het tevens ook mogelijk om meerdere instantiaties van een klasse te gebruiken.
voorbeeld 1.3 -- het instantieren van een klasse
[php]< ?php
class klassenaam
{
function klassenaam()
{
// code hier
}
}
$oKlasse = new klassenaam(); // instantieren van klasse => oKlasse is dus een object
?>[/php]
Bovenstaand voorbeeld definieert dus eerst een klasse (class) met de naam "klassenaam" ( hoe toepasselijk
).
Deze klasse bevat dus een functie die dezelfde naam heeft als de klasse zelf, men noemt dit een 'constructor' later meer hierover.
Waar het om gaat is de volgende regel:
Voorbeeld 1.4
[php]
$oKlasse = new klassenaam(); // instantieren van klasse => oKlasse is dus een object
[/php]
We instantieren hier de variabele $oKlasse als object van de klasse 'klassenaam'.
Instantiëren gebeurt dus op de volgende manier:
[php]
// oObject is dus het object van de geinstantieerde klasse 'klassenaam'
$oObject = new klassenaam(); [/php]
[ ! ] METHODS
Wanneer men gebruik maakt van een functie ín een klasse, wordt er gesproken over een method. Als een functie buiten een klasse staat, spreekt men over een functie.
KLASSE CONSTANTEN
Vanuit PHP4 kenden wij al de constanten, deze definieerden wij meestal als volgt:
[php]define("CONSTANTE_NAAM","met hier iets van een waarde");[/php]
In PHP5 kent men Klasse Constanten die ook slechts een keer aangemaakt worden en daarna niet meer gewijzigd kunnen worden, dit kun je als volgt doen:
[php]const CONSTANTE_NAAM = "hier iets qua waarde neerzetten...";[/php]
CONSTRUCTOR
In voorbeeld 1.2 gaven we al aan dat de method in deze klass dezelfde naam had als de klasse zelf.
Bij PHP4 werd hiermee een constructor gegenereerd. Een constructor is een method die bij het instantieren van een klasse direct uitgevoerd wordt. Deze wordt meestal gebruikt om variabelen een beginwaarde te geven ( initialisieren van een variabele ). In PHP5 kan de constructor zoals deze in PHP4 gebruikt wordt nog wel gebruikt worden, maar dit is niet aan te raden. PHP5 daarentegen kent een nieuwe functie genaamd __construct( ), deze wordt als volgt toegepast:
Voorbeeld 1.5
[php]< ?php
class klassenaam
{
function __construct()
{
// code hier
}
}
?>[/php]
Let op! - een constructor is een gemakkelijke manier om bijv. variabelen een initiële waarden te geven, maar is niet vereist.
DESTRUCTOR
In PHP5 kent men naast de constructor ook de destructor. De destructor wordt aangeroepen als het object niet meer gebruikt wordt. Hiermee vernietigd deze alles in het geheugen wat door het object gebruikt werd. Bij PHP-functies wordt dit automatisch al gedaan aan het object niet meer gebruikt wordt, maar wanneer er gebruik gemaakt wordt van een andere proces zoals een connectie met een MySQL server wordt deze niet automatisch gesloten. Hiervoor is het dus handig om een destructor te gebruiken.
Voorbeeld 1.6 - constructor en destructor
[php]
classe dbConnect()
{
private $conn;
function __construct()
{
$this->conn = mysql_connect("hostnaam","gebruiker","wachtwoord");
}
function __destruct()
{
if($this->conn)
{
delete($this->conn);
}
}
}
[/php]
We zien een aantal nieuwe dingen in bovenstaand voorbeeld.
Als eerste deze:
[php] private $conn; [/php]
In plaats van de var functie die in PHP4 gebruikt werd om variabelen aan te definieren binnen een classe zien we nu (in PHP5) private staan. Waarom deze functie vervangen is door private vertel ik later in dit artikel als we het gaan hebben over 'encapsulation'. Voor nu is het alleen belangrijk om te weten dat $conn een variabele binnen de klasse is.
Als tweede zien we:
[php]$this->conn = mysql_connect("hostnaam","gebruiker","wachtwoord");[/php]
Dit is een verwijzing binnen een klasse naar een variabele. De variabele conn wordt dus als resource toegewezen voor de functie mysql_connect();
(Een resource is een speciale variabele, die een referentie houdt met een externe bron. Een resource krijgt de waarde true als deze toegewezen is aan een externe bron.)
Als derde zien we:
[php]
if($this->conn)
{
unset($this->conn);
}
[/php]
Hieruit kunnen we opmaken dat wanneer $this->conn een resource is, deze door de destructor weer vernietigd wordt.
Naast unset() is nieuw in PHP5 de functie delete(), deze kan worden gebruikt om een object uit het geheugen te verwijderen.
Nieuw DOM, meer mogelijkheden
PHP5 kent een nieuw DOM (Document Object Model) ten opzichte van PHP4, hierdoor zijn er meer mogelijkheden gekomen qua OOP programmeren.
ENCAPSULATION
Omdat je soms niet wilt dat je gegevens overal toegankelijk zijn, bestaat er dankzij het nieuwe DOM in PHP5 encapsulation. Encapsulation is gegevens afscherming en hiermee kun je zowel methods als variabelen afschermen binnen klasses.
Binnen PHP5 kent men de volgende soorten afscherming:
- public
- private
- protected
Methods en variabelen overal direct toegankelijk, ook buiten de classes zelf
Methods en variabelen direct toegankelijk binnen de klasse waarin deze is gedefinieerd.
Methods en variabelen alleen binnen de 'eigen' klasse direct toegankelijk en in klasses die overgeërft worden, meer hierover later in dit artikel.
Om het een en d'ander gemakkelijk op een rijtje te zetten, heb ik onderstaand een toegankelijkheidstabel gemaakt.
Toegankelijkheids tabel
| Buiten klasse | Binnen klasse | Door overerving | |
| Public | ja | ja | ja |
| Private | nee | ja | nee |
| Protected | nee | ja | ja |
GETTERS EN SETTERS
Omdat PHP5 dus encapsulation kent en we hiermee bepaalde gegevens af willen schermen, bestaat er de mogelijkheid om van buiten de klasse, variabelen binnen de klasse te wijzigen. Dit kun je doen door de zogenaamde setters. Wanneer je buiten de code toch een waarde van een variabele, welke zich binnen de classe bevindt, toch wilt ophalen kun je een getter gebruiken.
Stel je voor je hebt het volgende 2 bestanden (1 - de klass, 2 - een index file oid)
[php]
// bestand >> class.mijnklass.php
class mijnklass
{
protected $sNaam;
// we gebruiken hier de PHP5 constructor!
// Tip! - een constructor is altijd public, dus behoeft geen encapsulation!
function __construct()
{
$sNaam = ""; // geef variabele initiele waarde.
}
private function setNaam($p_sNaam)
{
$this->sNaam = $p_sNaam;
}
private function getNaam()
{
return $this->sNaam;
}
}
[/php]
[php]
// bestand >> index.php
require(' class.mijnklass.php'); // we includen de class
$oKlass = new mijnklass();
print "Mijn naam is: ".$oKlass->sNaam;
$oKlass->setNaam("Ferdinant");
print "Mijn naam is: ".$oKlass->sNaam;
print "Mijn naam is: ".$oKlass->getNaam();
[/php]
Wanneer we het index.php bestand met bovenstaande code uit gaan voeren krijgen we het volgende als resultaat:
[php]
Mijn naam is:
Mijn naam is:
Mijn naam is: Ferdinant
[/php]
Hoe kan dit?
Als eerste gaan we kijken naar de variabelen binnen de klasse.
[php]protected $sNaam;[/php]
In het bestand index.php wordt bij de eerste keer dat deze geprint wordt de variabele direct aangeroepen.
Maar omdat deze de afscherming 'protected' kent, geeft deze dus geen waarde terug.
De tweede maal wanneer er geprint wordt, is nadat de setNaam method gebruikt is,
dit maakt ook niets uit, want de variabele is en blijft de afscherming 'protected' kennen.
De derde maal printen we maar de method getNaam();
Deze geeft de variabele wel terug omdat deze de afscherming 'private' kent.
Dit is in eerste instantie misschien moeilijk te begrijpen, ik zou zeggen oefen er wat mee, wellicht dat je het snel onder de knie krijgt.
GETTERS EN SETTERS IN PHP5
In PHP5 is een nieuwe functie geimplementeerd, namelijk : "__set()" en "__get()".
Het handige hiervan is, dat je bijvoorbeeld deze kunt gebruiken om automatisch een variabele te controleren.
Als voorbeeld nemen we even de volgende klasse:
[php]
class valideren
{
public $nWeekNummer;
function __set($p_sNaam, $p_vValue)
{
switch($p_sNaam)
{
case "nWeekNummer" :
if($p_vValue > 52)
{
trigger_error($p_vValue." is geen geldig weeknummer");
}
else
{
$this->nWeekNummer = $p_vValue;
}
}
}
function __get($p_sNaam)
{
$vReturn = "";
switch($p_sNaam)
{
case "nWeekNummer":
if($this->nWeekNummer > 52)
{
$vReturn = "Een weeknummer moet tussen de 0 en de 52 zitten....";
}
}
return $vReturn;
}
}
[/php]
Zoals je ziet zitten de nieuwe functies __set en __get in bovenstaand voorbeeld.
Als we nu het volgende script aanroepen:
[php]$oNieuw = new valideren();
$oNieuw->nWeekNummer = 42;
$oNieuw->nWeekNummer = 54;
print $oNieuw->nWeekNummer;
[/php]
Zal dit resulteren in een fout melding voor het setten (regel 3), want week 54 is geen geldig weeknummer, en een foutmelding voor het getten (regel 4), de variabele die verkregen wordt zit niet tussen de 0 en de 52.
INTERFACE
De bediening van een object is de manier waarop een object wordt behandeld. In OO-termen noemt men dit de interface van een object. De interface is de manier waarop 2 onderdelen van het systeem met elkaar (kunnen) praten. Omdat het soms handig is vooraf vast te leggen welke functionaliteit een klasse moet bevatten kun je interfaces gebruiken. Een interface dien je eerst zelf aan te maken en kan je dan in de klasse definitie opnemen.
Een voorbeeld van een interface:
[php]
interface iMijninterface
{
public function setNaam();
}
[/php]
Opnemen van een interface in een klasse definitie kun je doen door het woord implements te gebruiken.
Voorbeeld opnemen interface in klasse definitie
[php]
interface iMijninterface
{
public function setNaam();
}
class mijnklass implements iMijninterface
{
public function setNaam()
{
}
}
[/php]
Tevens is het mogelijk om meerdere interface te maken, dit kan door deze onder elkaar te plaatsen, bijvoorbeeld:
[php]
interface iMijninterface
{
public function setNaam();
}
interface iJouwinterface
{
public function eenanderemethod();
}
interface iRareinterface
{
public function eenMethod();
}
[/php]
Deze kun je dan vervolgens, indien gewenst, allemaal in 1 klasse definitie opnemen.
[php]class mijnKlasse implements iMijninterface, iRareinterface, iJouwinterface [/php]
OVERERVING (INHERITANCE)
Overerving is het mogelijk maken dat een klasse afleidbaar is van een andere classe. In feite neem je met overerving de methods en variabelen over in een andere klasse.
De hoofdklasse waarvan afgeleid wordt noemt men ook wel parent of base class. De klasse die de klasse overerft noemt men een subclass.
PARENT CLASS
|
|
|
V
SUBCLASS
Om het wat duidelijker te maken gaan we 2 classes maken, 1 als parent class en 1 als subclass.
[php]
// parent class
class laadBestand
{
private $m_sBestandsnaam;
function __construct()
{
$this->m_sBestandsnaam;
}
function setBestandsnaam($p_sBestandsnaam)
{
if (file_exists($p_sBestandsnaam)
{
$this->m_sBestandsnaam = $p_sBestandsnaam;
}
}
function getBestandsnaam()
{
return $this->m_sBestandsnaam;
}
}
// sub class
class tekstBestand extends laadBestand // hier gebeurt de overerving
{
function __construct()
{
}
}
[/php]
ABSTRACTE CLASSES
Naast het gebruik van interfaces (eerder in dit artikel besproken) kent PHP5 nu ook Abstracte Classes. Een abstract class is een class waarvan een of meerdere functies niet zijn geimplementeerd (ze hebben geen code), maar wel zijn gedeclareerd (de functie staat er wel). Een abstract class kun je daardoor niet los instantieren, maar je kunt wel een andere class ervan 'afleiden' door de abstracte class te extenden.
Mocht je bovenstaande materie snappen kijk dan ook nog even naar het volgende artikel op phpfreakz.nl over het toepassen van OOP.