Jump to content

[TUT: PHP] Klassen, deel 4: Klassen in praktijk 2


Recommended Posts

Geplaatst: (bewerkt)

PHP: Klassen



Deel 4: Klassen in praktijk 2

Deel 1: De basis

Deel 2: Basis uitbreiding

Deel 3: Klassen in praktijk 1

Deel 4: Klassen in praktijk 2

Introductie

Je vorige site in php werd op een gegeven moment een grote hooiberg. Overal stond code, je wist niet meer waar je moest zoeken. Aanpassingen waren nauwelijks mogelijk, en eigenlijk stond heel veel dubbel in je website, maar net weer een tikkie anders. Deze keer wil je het beter aanpakken, maar hoe?

Hiervoor kun je klassen gebruiken, waarmee je een structuur aanbrengt in je site. Je krijgt aparte klassen voor elk aparte onderdeel, hierbij kun je denken aan klassen voor je database, de gebruiker, de taal, error-handling, het systeem, de layout, etc...

In dit deel van de tutorial ga ik overerving uitleggen, en voorbeelding in de praktijk geven.

Herhaling

Als je dat nog niet gedaan hebt en nog weinig van klassen afweet, neem dan deel 1, deel 2 en/of deel 3 van deze tutorial door!

Deel 4

In dit deel ga ik uitleggen hoe je klassen in praktijk kunt gebruiken. Ik maak gebruik van meerdere voorbeelden.

Hier geef ik, in tegenstelling tot deel 3, kleine voorbeelden over het gebruik van klassen.

Evaluatie deel 3

Waarom is nou eigenlijk het systeem van deel 3, of een soortgelijk systeem gebaseerd op klassen, handig?

Eigenlijk heb je op het moment dat je class Page uitbreid met de betreffende klasse van de pagina, alle variabelen al klaarstaan. Je hebt een verbinding met de database, informatie over de gebruiker, etc.. Ook zit in het systeem verwerkt wat er moet gebeuren met foutmeldingen, en er zat een template- en taal-systeem in. Deze zijn allemaal te bereiken via die klasse Page, en door de overerving ook in je class Index, of welke klasse je ook maakt.

Je hoeft dus niet steeds op elke pagina een verbinding te maken met de database, of een header.php en footer.php te laden. Dit zit al in het systeem! Als je het systeem hebt, is het enige wat je nog moet doen op een specifieke pagina:

- init.php oproepen

- een klasse maken die class Page uitbreidt

- parent::__construct(); oproepen

- de output laten parsen

Voor de rest ben je in alles vrij!

Voorbeeld in praktijk #2

In PHP heb je niet geweldig veel aan klassen. Klassen zijn eigenlijk over komen waaien van programmeertalen als C/C++. Toch zijn er voordelen als je klassen gebruikt in PHP. Je code wordt er bijvoorbeeld overzichtelijker van, want de naam van de functie suggereert al wat een stukje code doet.

Maar wat kun je nog meer met klassen?

Er moet nog meer te doen zijn met de klassen. Laten we verder ingaan op de overerving.

Stel, je hebt een forum, een nieuws-systeem, en een gastenboek.

Wat hebben deze zaken overeen?

- elk bericht heeft een titel

- elk bericht heeft een auteur

- elk bericht heeft een bericht (dah :puh: )

- elk bericht heeft een datum

Je zou dus, in plaats van steeds alle HTML steeds te herschrijven voor elk zo'n systeem, één algemene klasse hiervoor kunnen gebruiken.

Je krijgt dat dus een algemene klasse genaamd 'MessageForm', welke je uitbreidt met klassen als 'ForumMessage', 'NewsMessage' en 'GuestbookMessage'. Het plaatsen, bewerken en eventueel verwijderen van berichten gaat dan via het MessageForm, de specifieke dingen die net het verschil maken tussen de 3 systemen plaats je in de uitbreidende klassen.

Een globaal overzichtje:

class MessageForm
function addForm(systeem) --> geef <form> met inhoud weer, leeg
function addSubmit(systeem) --> schrijf de info uit addForm naar de database (INSERT)

function editForm(systeem, id) --> geef <form> met inhoud weer, met het bericht, etc. van het meegegeven systeem en id
function editSubmit(systeem, id) --> schrijf de info uit editForm naar de database (UPDATE)

function delete(systeem, id) --> verwijder bericht

class ForumMessage extends MessageForm
function viewForum --> het forum-overzicht weergeven
function viewTopic --> een topic bekijken

class NewsMessage extends MessageForm
function addForm
	if(is_admin()) parent::addForm('news')
// nieuws kan alleen geplaatst worden door admins, dus ook alleen voor het toelaten
// hier de rest

class GuestbookMessage extends MessageForm
// spreekt wel voor zich...

Voorbeeld in praktijk #3

Stel, je maakt een spel waarin je een aantal winkels hebt. Je hebt een kledingwinkel, een caféetje en een wapenwinkel. In de eerste 2 moet je met wit geld 'betalen', in winkel 3 met zwart geld. Je maakt dat dus een klasse Winkels (of class Shops) waarin je de overzichten van de winkel-voorraad uitstalt, en 3 uitbreidende klassen voor de kledingwinkel, cafe en wapenwinkel, waar je de 'betaling' afhandelt (o.a. verschil tussen wit en zwart geld).

#2 verder uitwerken: Terugkoppeling

We gaan weer terug naar de berichten (#2), maar we blijven bij het gastenboek.

Stel, iemand typt een bericht, maar je komt erachter dat hij zijn naam vergeten is. Je hebt het bericht in je $_POST, maar als je op vorige drukt krijgt de bezoeker weer een leeg form. Kan hij weer opnieuw beginnen.

Dat kan beter. Welke informatie krijgen we binnen? Een titel, een auteur(-snaam), en een bericht.

Nu gaan we, als er een fout optreedt, terugkoppelen naar het form.

Hoe doen we dat? Hier een globaal voorbeeld (even zonder taal-klasse, en verder ook niet compleet uitgewerkt):

<?php
// messageForm.class.php
require("../includes/init.php");

class MessageForm extends Page {
public function __construct() {
	parent::__construct('messageForm');
	$this->template->setVar('melding', '');
}

protected function addForm($titel='', $auteur='', $bericht='') {
	$this->template->setVar('titel', $titel);
	$this->template->setVar('auteur', $auteur);
	$this->template->setVar('bericht', $bericht);
}

protected function addSubmit() {
	$titel = $_POST['titel'];
	$auteur = $_POST['auteur'];
	$bericht = $_POST['bericht'];
	if(empty($titel) || empty($auteur) || empty($bericht)) {
		$this->template->setVar('melding', 'Je bent iets vergeten in te vullen!');
		$this->addForm($titel, $auteur, $bericht); // terugkoppeling!
		return; // bij een return wordt de functie 'afgesloten', dus onderstaande in de functie wordt dan niet meer uitgevoerd
	}

	$this->db->edit("INSERT INTO ....");

}
}
?>

(NB: merk hierboven de terugkoppeling op ;) )

<?php
// guestbookMessage.php
require("messageForm.class.php");

class GuestbookMessage extends MessageForm {
public function __construct() {
	parent::__construct();
	if($_GET['action'] == 'plaats') {
		$this->addForm();
	}
	elseif($_POST['action'] == 'plaats') {
		$this->addSubmit();
	}

	$this->template->parse();
}
}

$GM = new GuestbookMessage();
?>

(NB: een dubbele extend kan dus ook, maar wel indirect (GuestbookMessage --> MessageForm --> Page))

<?php
// messageForm.php, template-bestand
?>
<!-- eigenlijk moet de form action automatisch, en niet hardcoded... -->
<form action="guestbookMessage.php" method="post">
<div>
	<?=$vars['melding']?><br>
	<br>
	Naam: <input type="text" name="auteur" value="<?=$vars['auteur']?>"><br>
	Titel: <input type="text" name="titel" value="<?=$vars['titel']?>"><br>
	Bericht: <textarea name="bericht"><?=$vars['bericht']?></textarea><br>
</div>
</form>

Als er dus iets fout is, kun je door middel van de functies makkelijk terugkoppelen. Dit zou niet mogelijk zijn als je geen klassen gebruikt, of eigenlijk: als je geen functies gebruikt. Maar ja, om de functies te ordenen, gebruik je weer klassen.

#2 verder uitwerken: Vereenvoudigen

Weer in het gastenboek heb je een paar opties:

- bericht plaatsen

- bericht bewerken

- bericht verwijderen

Het bericht plaatsen en bewerken maakt in principe gebruik van hetzelfde form, niet?

Waarom zou je hier dan niet 1 van maken?

We strepen dus de functies editForm en editSubmit even weg, we kunnen het met addForm en addSubmit af (met eventueel andere namen).

De functies addForm en addSubmit worden dan weliswaar wat ingewikkelder, maar je hebt nog minder dubbele data!

Einde deel 4

Dit was deel 4 van deze tutorial. Ik hoop dat je er wat van opgestoken hebt!

Beoordelingen, correcties en tips zijn welkom!

Bewerkt: door marcootje
Geplaatst:

Ik moet zeggen, je tutorials zijn zeer uitgebreid en steek er toch heel wat van op. Ik hoop dat je zo door gaat, er is werkelijk niks aan op te merken :tu:

  • 3 weken later...
Geplaatst:

Prima tutorial maar ik heb een vraagje soms zie ik zulke Classes:

class Welcome extends AndereClass {

function Welcome()
{
	parent::AndereClass();	
}

function index()
{
	/**
	 * Meer code
	 */
}
}

Eerst maak je dus een Klasse die gebasseerd is op AndereClasse. Dan maar je een functie Welcome (die verwijst naar de naam van de Classe denk ik). Maar dan? Zorgt die parent::AndereClasse ervoor dat de constructor van AndereClasse wordt geladen?

Bedankt!

Geplaatst: (bewerkt)

Leuke vraag.

Zoals je in deel 1 kan lezen, heeft php 4 een andere aanpak voor constructors dan php 5.

In php 5 is de constructor __construct(), in php 4 is het de klassenaam (*klassenaam*()).

Dat sluit dus volledig op jouw script aan: Welcome() is van class Welcome de constructor, AndereClass() is van AndereClass() de constructor.

Omdat een constructor van een klasse die ge-extend wordt niet automatisch wordt uitgevoerd, moet je die aanroepen met bijv. parent::AndereClass();

In de meeste scripts die voor php 5 zijn geschreven, moet je de constructor aanroepen als parent::__construct();. Het ligt er dus gewoon aan welke soort constructor er aanwezig is in de klasse.

In php 5 kijkt de parser eerst of er een __construct() is, en als die niet bestaat of er een *klassenaam*() is. Als die er beide niet zijn, is er geen constructor (ook niet erg, mag gewoon).

Dus inderdaad, parent::AndereClass() zorgt ervoor de de constructor van AndereClass wordt aangeroepen.

Ik hoop dat het zo duidelijk is.

Bewerkt: door marcootje
Geplaatst:

Aha, bedankt dus als ik het goed beschijf een klas als deze:

	 <?php

 class Marco
 {
 function __contruct()
 {
 $naam = 'Marco';
 }
 }
 ?>

Is dus in PHP4:

   <?php

  class Marco
  {
  function Marco()
  {
  $naam = 'Marco';
  }
  }
  ?>

Hartstikke bedankt!

Geplaatst: (bewerkt)

[fail]Dat wist ik wel :engel: [/fail]

Thanks, ik ben nu OOP aan het leren maar ik heb een vraag:

	 <?php

  <?php

class Product
{
	private $_type = 'DVD';

	public function GetProductType()
	{
		return( $this->_type );
	}

	public function SetProductType( $type )
	{
		$this->_type = $type;
	}
}

?>

En ik heb deze code om de class aan te roepen:

 <?php

 require_once( 'product.php' );

 $product = new Product();

 $product->SetProductType( 'Haas' );

 echo( $product->GetProductType() );

 ?>

Het gekke is dat ik geen error krijg. Dus je kan de beveiligde properties wel wijzigen via functions?

Bedankt!

EDIT: lol foutje...

Bewerkt: door -Omar-
Geplaatst: (bewerkt)

inderdaad, via een public function kun je een private variabele gewoon veranderen/ophalen ;) (staat ook ergens in de tut)

Bewerkt: door marcootje
Geplaatst:

Sorry voor de dubbelpost maar ik ben op een missie van god.

Deze code:

 Class::Query( 'SELECT id, naam, info FROM leden WHERE id = 1' );

Is dus eigenlijk om te voorkomen dat je steeds dit moet doen:

 $var = new Class();
$var->Query( 'SELECT id, naam, info FROM leden WHERE id = 1' );

Maar je zegt in de tut dat je :: gebruikt als je geen __construct gebruikt maar in een class als deze:

 class Blog extends Controller
{
 public function __construct()
 {
  parent::__construct();
 }

}

Gebruik je :: toch? Of is dat weer anders omdat je hem in de class gebruik want ik kan niet dit doen volgensmij:

 Class::__construct();

Bedankt, sorry voor de wazige uitleg :puh:.

- Omar

Geplaatst:

parent is een speciaal geval, en kan eigenlijk niet aangegeven worden met een pijl (->).

Dit is omdat er geen variabele is die de parent klasse bevat. Het is zomaar een keyword.

Als je niet snapt waarom parent met :: moet, moet je maar gewoon accepteren dat het met :: moet, het is gewoon zoals het hoort ;) .

Over die database-klasse, deze hoef je niet steeds opnieuw te maken.

$var = new Class();
$leden = $var->Query( 'SELECT id, naam, info FROM leden WHERE id = 1' );
$nieuweLeden = $var->Query( 'SELECT id, naam, info FROM nieuweLeden WHERE id = 1' );
$senioren = $var->Query( 'SELECT id, naam, info FROM senioren WHERE id = 1' );

dat kan ook gewoon. Je maakt gewoon een algemene variabele voor de database.

Een reactie plaatsen

Je kan nu een reactie plaatsen en pas achteraf registreren. Als je al lid bent, log eerst in om met je eigen account een reactie te plaatsen.

Gast
Op dit onderwerp reageren...

×   Je hebt text geplaatst met opmaak.   Opmaak verwijderen

  Only 75 emoji are allowed.

×   Je link is automatisch ingevoegd.   In plaats daarvan weergeven als link

×   Je vorige bewerkingen zijn hersteld.   Alles verwijderen

×   You cannot paste images directly. Upload or insert images from URL.

  • Recent actief   0 leden

    • Er zijn hier geen geregistreerde gebruikers aanwezig.
×
×
  • Create New...