oke na uitstekende hulp zoals altijd hier van onder andere Wouter en Erwin heb ik maar even geprobeerd om zonder tutorials etc een class te bouwen. (wel kijken naar de linkjes van wouter) want het was idd nog een beetje kopieren en plakken met OOP maar ik ben nu wel op de goede weg denk ik. heb begin gemaakt met een class 'databaseConfig' hier staat de database configuratie in. dan heb ik vervolgens een class gemaakt genaamd 'databaseConnect' hier ga ik connecten met de database. maar nu. snap ik een paar dingen niet.
wat is het verschil tussen
abstract class ...
en
class ...
en moet ik nu de databaseConnect extenden uit de databaseConfig of moet ik hier de __construct gebruiken zoals __construct(databaseConfig)? of denk ik nu helemaal verkeerd?
Nee Jeroen, een configuratie heeft niks met een connectie te maken. Configuratie is een onderdeel van je verbinding, maar een configuratie is niet je verbinding. Dat zijn 2 totaal verschillende objecten.
Een extend relatie (extenden) moet je zien als een IS_EEN relatie. Extenden doe je als iets ietsanders is. Bijv. een hond IS EEN dier, een Renault Twingo IS EEN auto, een sessie IS EEN opslagmethode.
In al deze dingen heb je de superklasse: dier, auto, opslagmethode. En je hebt de subklassen: hond, renault twingo, sessie. De subklassen extenden de superklasse.
[hr]
OO bestaat eigenlijk uit 2 onderdelen:
- Object Geörienteerd scripten
- Flexibel en aanpasbaar maken van je code
Interfaces en abstracte klassen hebben met dat 2e te maken. Je wilt nooit iets dubbel hoeven schrijven. Daarmee bedoel ik dat je dit niet wilt:
<?php
class Admin
{
protected $name;
protected $rang;
public function __construct($name)
{
$this->name = $name;
$this->rang = 10;
}
public function getName()
{
return $this->name;
}
public function getRang()
{
return $this->rang;
}
}
class User
{
protected $name;
protected $rang;
public function __construct($name)
{
$this->name = $name;
$this->rang = 1;
}
public function getName()
{
return $this->name;
}
public function getRang()
{
return $this->rang;
}
}
?>
De meeste van deze klassen bevatten dubbele code. Dat kan je oplossen door een superklasse te maken waarvan beide de methoden extenden:
<?php
class Person
{
protected $name;
protected $rang;
public function __construct($name)
{
$this->name = $name;
$this->rang = 10;
}
public function getName()
{
return $this->name;
}
public function getRang()
{
return $this->rang;
}
}
class Admin extend Person
{
// ...
}
class User extend Person
{
// ...
}
?>
Alleen nu hebben we een probleem. Hoe gaan we het nu oplossen met de rangen? Nu hebben ze beide 10 als rang, terwijl de User rang 1 moet hebben.
De oplossing is werken met een abstracte klasse. Hiermee kun je sommige methoden vaststellen (zoals getName, getRang) en andere open laten, die moet de subklasse invullen. Deze methoden zijn de abstracte methoden. Het mooie daarvan is dat we verplichten dat de subklasse die methode moet hebben, maar wat hij doet dat gaat de superklasse niet aan.
Om deze code nog wat meer flexibel te maken gaan we de laatste duplicated code (de constructor) in 2 stukken splitsen: Het setten van de naam en het setten van de rang.
Het setten van de naam doen we in de constructor, alleen het setten van de rang doen we in een private method setRang. Hierdoor kunnen we in de abstracte superklasse alle dubbele code overnemen uit de subklassen en hebben we in de subklassen alleen unieke code:
<?php
class Person
{
protected $name;
protected $rang;
public function __construct($name)
{
$this->name = $name;
$this->setRang(); // roep onze, door de subklasse aangemaakte, setRang method aan
}
public function getName()
{
return $this->name;
}
public function getRang()
{
return $this->rang;
}
// laat deze method invullen door de subklasse
abstract private function setRang();
}
class Admin extend Person
{
// voeg rang = 10 toe
private function setRang()
{
$this->rang = 10;
}
}
class User extend Person
{
// voeg rang = 1 toe
private function setRang()
{
$this->rang = 1;
}
}
?>
@terence ah nu snap ik de nut van abstractie. in dit geval kan de databaseConfig geen abstrace class worden omdat geen enkele andere class de configuratie kan gebruiken die daar in zit. heb ik dit goed?
maar het databaseConnect kan databaseConfig wel extenden toch omdat het de info daaruit gebruikt om een verbinding op te zetten. denk ik nu zo goed?
@jeroen ja ik dacht wat als ik nu de configuratie nodig heb voor een andere sql type bijv mysqli of pdo. dan moet ik de configuratie kunnen gebruiken in die classes toch? hoef ik niet weer alles erin te tikken. of geld dit hier niet voor op een of ander manier?
In wat meer worden.
Een abstracte class kan zoals Terence al zegt abstracte methodes bevatten. Belangrijker echter is dat een abstracte class niet geinstantieerd kan worden, je kan de abstracte class zelf dus niet gebruiken, je kan er alleen een afgeleide class op schrijven die de eventuele abstracte functies erin implementeert en verder uitbreid.
Het nut van een abstracte class is dat je bepaalde functionaliteit die je in verschillende classes wil inbouwen al kan definieren en dus kan gebruiken op meerdere plekken. De abstracte functies erin kan je dan weer gebruiken om af te dwingen dat bepaalde functies zullen worden geimplementeerd door de afgeleide classes. Als je dat namelijk op die manier afdwingt, kan je functies in de abstracte class al aanroepen, zonder dat je weet hoe het geimplementeerd gaat worden.
En voor de duidelijkheid, een abstracte class kan abstracte functies bevatten, maar hoeft niet. Als echter een class een abstracte functie bevat, dan moet de class abstract zijn.
Edit: beetje mosterd na de maaltijd. Ik zie nu pas de hele lap tekst van Wouter :-)
@wouter ik had je reactie nog niet gelezen omdat ik weer reactie aan het tikken was maar heb het nu doorgelezen en je legt het wederom keurig uit! keurige voorbeeldjes. zo leer ik het nog te snel ;)
@Erwin ik snap het helemaal. alles wat je verwacht te gebruiken ( zoals een rang setten dan weet je dat je een abstracte class gaat gebruiken) en voor bijv de auto klasse een fuel abstracte ( gaat er bijv in een auto diesel in en in de andere petrol )
maar bijv in een database connection classe die ik nu aan het maken ben kan ik dus absoluut geen abstractie gebruiken toch? want er is maar 1 manier om te connecten. maar ik denk nu dus bij mezelf. nee het kan wel. want je hebt verschillende databases dus dan kan je daar een abstractie voor maken. denk ik nu zo goed of..?
Reshad, ja dat heb je goed. En met die gedachte stap je al over het de 2e stuk van OO: Het flexibel maken van code met patterns. Want je bent nu bezig met het Adapter Pattern.
Even een vraag voor je: Probeer eens een goed overzicht te tekenen van deze klassen. Welke is abstract en welke niet en welke extends welke?
[hr]
Merk overigens op dat je ook nog een interface hebt. Hiermee kan je klassen aan elkaar koppelen. Je weet dan eigenlijk nog geen 1 methode hoe je ze moet afhandelen, alleen je weet wel dat je straks zeker wilt zijn dat klassen bepaalde methoden bevatten. Later kun je in andere klassen dan kijken of ze afstammen van die Interface, waarmee je zeker weet welke methoden ze bevatten. Wat die methoden precies doen boeit je dan niks, als ze maar doen wat ze moeten doen.
En dan ga je komen naar 1 van de ontwerpprincipes: Programmeer naar een interface/superklasse i.p.v. naar een implementatie/subklasse. Probeer dus altijd superklassen te vinden en probeer zo min mogelijk over te laten aan de subklassen.
Als je kijkt naar die connectie class moet je denk ik niet zozeer rekening houden met mysql, mysqli of pdo. Dat is een technische keuze waar je als het eenmaal werkt, niet veel meer aan hoeft te doen. Je zal de een of de ander gebruiken.
Wat mijns inziens zinvoller is, is om na te denken over wat voor soort database te gaat gebruiken. Op het moment gebruik je waarschijnlijk MySQL, maar bij een volgend project is dat misschien MSSQL, of nog later Oracle of DB2.
Dan wordt het van belang om ervoor te zorgen dat je verschillende connectie objecten kan hebben voor de verschillende database systemen. De rest van je classes zal het worst zijn (met een kleine slag om de arm voor specifieke SQL verschillen), die willen gewoon een connectie kunnen maken en queries kunnen uitvoeren.
Wat je dan kan doen is een interface schrijven die bepaalt welke methodes de verschillende connection classes moeten implementeren. Zo kan je ervoor zorgen dat je andere database classes altijd de connection class kan aanspreken, voor welke DB het ook is.