Functies en Bestanden organiseren

Functies

Functies doen het werk voor ons. Wij roepen ze op, vaak met speciale wensen, en krijgen iets gedaan of iets terug. Denk aan een restaurant waar je een bestelling opgeeft en een lekker gerecht geserveerd krijgt.

We hebben al diverse ingebouwde functies gebruikt: var_dump(), isset(), strlen(), count(), sort(). Er zijn verschillen!

var_dump() en sort() doen iets voor ons (een overzicht uitprinten, een array sorteren) en that’s it. In een restaurant zou je bijvoorbeeld kunnen vragen of de tafel schoon gemaakt kan worden.

isset(), strlen() en count() daarentegen geven iets terug, iets wat we dan verder verwerken (zoals opeten).

Uiteraard kunnen we ook onze eigen functies schrijven. Het schrijven van een functie is als het uitbesteden van werk. Je schrijft broncode en geeft het een naam. Dat stukje broncode kan je dan aanroepen. Het is heel goed in het doen van een speciale klus (bijvoorbeeld het maken van salades).

Functie definiëren

Bij het definiëren van de functie leggen we vast wat deze moet doen.

function doeIets() {
  // Hier komt de functiebody.
}

Een uitgewerkt voorbeeld:

function groeten()
{
  $uur = date('H');
  if ($uur < 12) {
    return 'Goedemorgen!';
  } elseif ($uur < 18) {
    return 'Goedemiddag!';
  } else {
    return 'Goedenavond';
  }
}
  • We beginnen altijd met keyword function.
  • Daarachter komt een naam, die duidelijk maakt wat de functie doet. Omdat functies werk verrichten gebruiken we er in ieder geval ook een werkwoord bij.
  • De variabele $uur is alleen binnen de functie bekend.
  • Met return geven we iets terug. De aanroepende broncode kan dit dan weer gebruiken om zijn werk te doen.
  • Zo gauw een return is uitgevoerd, stopt de functie. Broncode die daarna komt wordt niet meer uitgevoerd.

Functie aanroepen

Een functie doet niks uit zichzelf. Pas als iemand de opdracht geeft, de functie bij zijn naam roept, komt deze in actie.

echo '<p>' . groeten() . '<p>';
  • Een functie aanroepen doen we door de naam en daarachter ronde haakjes te typen.
  • Als een functie iets teruggeeft (return), kan het resultaat meteen verder verwerkt worden. In het voorbeeld hierboven wordt de tekst die teruggegeven wordt tussen andere tekst (in dit geval HTML-elementen) geplakt en daarna met een echo op de webpagina geplaatst.

Parameters

Omdat we vaak speciale wensen hebben (‘breng een biertje’ in plaats van ‘breng iets’), schrijven we meestal functies met parameters.

function doeIets($metDit, $enDat) {
}

Functie met parameter(s) definiëren

function groetenMetNaam($naam) {
  $uur = date('H');
  if ($uur < 12) {
    return "Goedemorgen, $naam!";
  } elseif($uur < 18) {
    return "Goedemiddag, $naam!";
  } else {
    return "Goedenavond, $naam!";
  }
}

Een voorbeeld van een functiedefinitie met een parameter:

  • Deze functie verwacht een parameter $naam, dat betekent dat ze alleen werkt als je ook een naam meegeeft als argument bij het aanroepen.
  • $naam is ook een lokale variabele, die alleen binnen de functie bekend is.
  • Met return wordt weer een tekst (string) teruggegeven. Deze keer met de naam die bij het aanroepen is ingevuld erin verwerkt.

Een functie met parameter aanroepen

echo '<p>' . groetenMetNaam('Robert') . '</p>' ;

En hier de oproep van de hierboven gedefinieerde functie met de string 'Robert' als argument:

  • Hier wordt Robert gegroet.
  • Bij het aanroepen van de functie bepaal ik, wie ik wil groeten.
  • Later zal de bezoeker van onze website zijn naam invullen en dan kunnen wij haar/hem met zijn naam welkom heten.
  • Bij het aanroepen noemen we dat wat we aan de functie meegeven meestal een argument.
  • Ook hier wordt weer de teruggegeven tekst verder verwerkt en uiteindelijk getoond.

Parameters met default waarde

Uiteraard kunnen we ook meerdere parameters gebruiken. De laatste (of twee, drie laatsten) kunnen ook optioneel zijn. Daarvoor geven we de parameter bij het definiëren een default (standaard) waarde.

function aanhef($voornaam, $achternaam, $tussenvoegsel = "") {
  return "Beste $voornaam $tussenvoegsel $achternaam, <br>";
}

function dobbelen($hoogste = 6) {
  return mt_rand(1, $hoogste);
}
  • Bij aanhef() hebben we drie parameters, $voornaam en $achternaam zijn verplicht om bij het aanroepen van de functie in te vullen, $tussenvoegsel is optioneel.
  • $tussenvoegsel krijgt als standaardwaarde een lege string mee.
  • de functie dobbelen() kunnen we zonder argument aanroepen.
  • de variabele $hoogste wordt dan automatisch zes (het hoogste cijfer van een dobbelsteen). Maar we zouden net zo goed met een dobbelsteen met 20 zijden, etc. kunnen spelen.

Zo kun je de functies gebruiken:

echo '<p>' . aanhef("Jan", "Sloot", "van der") . '</p>';
echo '<p>' . aanhef("Piet", "Veenstra") . '</p>';

echo '<p>Je gooit een <span>' . dobbelen(20) . '</span></p>';
echo '<p>Je gooit een <span>' . dobbelen() . '</span></p>';
  • Functieoproepen met en zonder optionele parameters.
  • Verplichte parameters moeten wel worden ingevuld.

Global scope

Zoals onder Functies beschreven, zijn variabelennamen binnen een functie alleen daar bekend. Elke functie is een eigen wereld. De communicatie met de buitenwereld gebeurt via de argumenten (invoer) en de returnwaarde (uitvoer).

Het is echter mogelijk voor speciale gevallen om via het keyword global toegang tot een globale variabele te krijgen. Hier laat ik een voorbeeld zien en benoem ik daarna de bijzonderheden.

$config = ['websitenaam' => 'WebTech International', 'taal' => 'nl'];

function genereerHead() {
  global $config;
  $html = <<<HEAD                  // Begin van een HEREDOC-constructie
  <!DOCTYPE html>                  // inhoud van HEREDOC. Er hoeft niet op
  <html lang="$config['taal']">    // aanhalingstekens gelet te worden.
  <head>
    <meta charset="UTF-8">
    <title>$config[websitenaam]</title>
  </head>
HEAD;                              // Einde van HEREDOC (er mag geen spatie voor staan).
  return $html;
}

echo genereerHead();
  • Er wordt een array met diverse algemene instellingen voor een website aangemaakt.
  • Binnen de definitie van de functie genereerHead() wordt met global verwezen naar de globale $config met instellingen voor deze website.

HEREDOC

Bij het aanmaken van de string-variable $html maken we hierboven gebruik van de zogenoemde HEREDOC-syntaxis. Deze kan vooral gebruikt worden als we grotere stukken HTML-code binnen PHP mee willen nemen. We hebben dan minder gedoe met aanhalingstekens.

  • Een HEREDOC-blok wordt aangezet door <<<EENNAAMINHOOFDLETTERS
  • Daarna kan gewoon HTML-code worden geplaatst, met eventueel PHP variabelen ertussenin
  • Het blok wordt weer afgesloten met weer EENNAAMINHOOFDLETTERS. Deze moet echter op een eigen regel en dan helemaal vooraan (ook geen spaties) worden geplaatst.
  • De sleutels van arrayelementen worden zonder aanhalingstekens geschreven.

Broncode in aparte bestanden organiseren

Het is Good Practice om broncode die we vaker nodig hebben in aparte bestanden op te slaan. Dat kan HTML-broncode zijn die op elke pagina meer of minder hetzelfde is of PHP-broncode die op meerdere plekken tussengevoegd moet worden. Omdat we PHP-broncode sowieso vaak in aparte functies plaatsen kunnen we het beste deze functies in eigen bestanden opslaan.

require_once

Als require_once het vereiste bestand niet kan vinden, geeft PHP een foutmelding en wordt de verdere uitvoer afgebroken. require_once wordt gebruikt om benodigde functies te laden. Het is niet geschikt om letterlijk een stuk PHP-broncode middenin een PHP-bestand in te voegen. Maar invoegen is een slechte praktijk, omdat hierdoor de broncode binnen één bestand onleesbaarder, en ook de interactie tussen broncode in het ene en het andere PHP-bestand ondoorzichtiger wordt. Bij require_once wordt voorkomen dat een functie vaker geladen wordt als hetzelfde require_once-statement herhaald wordt uitgevoerd (binnen alle broncode die in één keer uitgevoerd wordt, dus voor het produceren van één response). Deze herhaling kan voorkomen bij een uitgebreide applicatie met veel broncode verdeeld over veel bestanden.

<?=
require_once 'components/footer.php';
require_once 'components/header.php';
require_once 'components/overzicht.php';

maakHeader();
?>
<main>
  <h2>Diverse onderwerpen</h2>
  <p>Met een heleboel tekst ...</p>
  <?=
    maakOverzicht('fietsen');
  ?>
</main>
<?=
HTML_FOOTER
?>
  • Met require_once 'components/overzicht.php'; voert PHP een PHP-bestand overzicht.php uit waarin verschillende functies zijn gedefinieerd. Als deze component bijvoorbeeld al vanuit eerdere bezochte pagina is ingeladen haalt PHP het resultaat daarvan op uit het geheugen.

  • maakOverzicht() is een functie die in components/overzicht.php gedefinieerd staat en door de require_once-statement bovenaan beschikbaar is om aan te roepen.

  • In components/footer.php bestaat een functie maakFooter() en wordt alvast op de volgende manier een constante gemaakt voor de footer (die voor alle pagina’s hetzelfde is).

    define('HTML_FOOTER', maakFooter());
    

    Op deze manier hoeft de vaste HTML-broncode van de footer niets telkens opnieuw geschreven te worden. Ook wordt maakFooter() niet iedere keer opnieuw aangeroepen als er een pagina geproduceerd wordt. Dat zou wel zo zijn als de aanroep maakFooter() onder </main> geschreven was.