Code on top - View at bottom

Inleiding

Beginnende php-ers hebben de neiging om functionele php code tussen de HTML te plaatsen. Dit komt helaas deels doordat dit ook in literatuur te lezen valt. In deze tutorial leg ik uit waarom je dat niet moet doen.

Dynamische pagina

Hieronder zien we het verloop van een heel eenvoudig script die aan de hand van de tijd bepaalt wat de output moet worden.

program flow

Vragen we aan de gemiddelde hobbist om hier een php script voor te schrijven dan zou dat er ongeveer zo uit kunnen zien:

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Gegroet</title>
    </head>
    <body>
        <h1>
            <?php
                $hour = date('G');

                if($hour < 6) {
                    echo 'Goedenacht';
                } elseif($hour < 12) {
                    echo 'Goedemorgen';
                } elseif($hour < 18) {
                    echo 'Goedemiddag';
                } else {
                    echo 'Goedenavond';
                }
            ?>
        </h1>
    </body>
</html>

Al lijkt dit goed te werken zal de auteur zichzelf toch in de vingers gaan snijden. Want wat nu als we de woorden Goedenacht, Goedemorgen, Goedemiddag en Goedenavond in de titel willen zetten? We komen dan nu al in de problemen omdat we enerzijds het juiste woord niet in een variabele hebben staan maar direct tussen de HTML plaatsen met behulp van een echo en anderzijds omdat we niet zijn begonnen met de functionaliteit van het programma maar direct zijn begonnen met het uitspugen van HTML.

Code on top

Laten we de twee bezwaren die we hebben gaan oplossen. We verplaatsen als eerste het hele blok met php code naar boven en in plaats van de tekst direct met echo te versturen slaan we deze op in een variabele. Daarna hoeven we slechts nog twee echo's tussen de HTML te plaatsen.

<?php

$hour = date('G');

if($hour < 6) {
    $greeting = 'Goedenacht';
} elseif($hour < 12) {
    $greeting = 'Goedemorgen';
} elseif($hour < 18) {
    $greeting = 'Goedemiddag';
} else {
    $greeting = 'Goedenavond';
}

?>
<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title><?php echo $greeting; ?></title>
    </head>
    <body>
        <h1><?php echo $greeting; ?></h1>
    </body>
</html>

Zoals je ziet kunnen we nu de variabelen invoegen waar we willen en bovendien is onze code ook beter leesbaar geworden.

Meer redenen

Er zijn echter nog meer goede redenen om de functionele PHP code bovenin te plaasten en de output onderin. Hier volgen de belangrijkste:

1) Redirect

Soms willen we een gebruiker doorsturen naar een andere pagina, bijvoorbeeld na het verwerken van een formulier. We doen dat het beste met behulp van de header functie.

// stuur de client door naar een ander pagina:
header('Location: confirmation.html');
exit;
We moeten echter wel weten dat dit in de http header komt te staan van het antwoord (response) dat we gaan terugsturen naar de client. Deze http header wordt verstuurd zodra het script de eerste output verstuurt, met andere woorden moeten we van de header functie gebruik maken voordat we output versturen.

Onder output verstaan we een echo, HTML maar ook een enkele spatie, carriage return, tab of ieder ander karakter. Daarnaast zijn er nog editors die een zogenoemde BOM (Byte Order Mark) in het begin van een bestand plaatsen waardoor de header functie niet meer zal werken en mogelijk een foutmelding geeft. Gebruik dus een geschikte editor en begin je script direct met <?php.
2) Foutmeldingen

Als ons programma onverhoopt een foutmelding veroorzaakt dan willen we deze foutmelding niet op elke willekeurige plek tussen de HTML hebben. Doen we dat wel dan kan het gebeuren dat deze foutmelding niet of op een vreemde manier op het scherm komt te staan omdat de foutmelding tot gevolg kan hebben dat de HTML niet meer geldig is en de browsers hier niet meer goed mee om kunnen gaan. Daarnaast als de foutmelding komt voordat we met de output begonnen zijn kunnen we er nog voor kiezen om een andere template te gebruiken om de foutmelding netjes en overzichtelijk weer te geven.

3) Separation of concerns

Separation of concerns is een populaire spreuk onder professionele programmeurs. Het betekent niets anders dan dat we verschillende programma onderdelen netjes van elkaar willen scheiden zodat de code geordend en meestal ook in verschillende directories wordt bewaard. Zo wordt in professionele systemen de HTML eigenlijk altijd in een apart bestand en samen met andere templates in een aparte directory opgeslagen. Het bestand met de HTML wordt dan meestal de view genoemd.

4) Templates

Als we met php code beginnen en de HTML in aparte templates (bestanden) zetten dan kunnen we ook afhankelijk van het verloop van het programma een keuze maken uit meerder templates. Templates kunnen ook andere formaten ondersteunen dan alleen HTML. Zo zou er ook een template kunnen zijn voor plain-text, XML, JSON, CSV of PDF. Onderstaand voorbeeld zal dit verduidelijken.

template.php ( probeer http://localhost/template.php?type=html of http://localhost/template.php?type=xml )
<?php
/*
 * Deze functie includes een template
 */
function renderTemplate($filename, $data) {
     extract($data);
     include 'templates/' . $filename . '.php';
}

/*
 * Wat data ten behoeve van de templates
 */
$userInfo = array(
    'username' => 'Frank Beentjes',
    'email' => 'frankbeen@gmail.com',
    'role' => 'administrator'
);

/*
 * standaard output is html
 */
$outputType = 'html';

/*
 * indien in de url ?type=xxx staat
 */
if(isset($_GET['type'])) {
    $outputType = strtolower($_GET['type']);
}

/*
 * indien in de url ?type=xml staat render dan XML
 */
if($outputType == 'xml') {
    header ("Content-Type:text/xml"); 
    renderTemplate('userinfo.xml', $userInfo);
} else {
    /*
     * anders HTML
     */
    renderTemplate('userinfo.html', $userInfo);     
}
templates/userinfo.html.php
<!DOCTYPE html>
<html>
    <head>
        <title>User information</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <table>
            <tr>
                <th>Username:</th>
                <td><?php echo $username; ?></td>
            </tr>
            <tr>
                <th>Email:</th>
                <td><?php echo $email; ?></td>
            </tr>
            <tr>
                <th>Role:</th>
                <td><?php echo $role; ?></td>
            </tr>
        </table>
    </body>
</html>
templates/userinfo.xml.php
<?xml version="1.0" encoding="UTF-8"?>
<user>
  <username><?php echo $username; ?></username>
  <email><?php echo $email; ?></email>
  <role><?php echo $role; ?></role>
</user>

template.php zal afhankelijk van de GET variabele type de userinfo.html.php of userinfo.xml.php template includen en dat resulteert dan in een HTML pagina of een XML pagina.

Wat mag wel in de view

In de view mogen alleen php blokken geplaatst worden die bedoeld zijn om (de juiste) variabelen of stukken HTML, XML, plain-text e.d. te versturen. Meestal bestaat dit uit de volgende keywords: echo, while, for of foreach, if, else, endif, count of include. Onderstaand voorbeeld is een typische template die een aantal records uit de database laat zien:

<!DOCTYPE html>
<html>
    <head>
        <title>User information</title>
        <meta charset="UTF-8">
    </head>
    <body>
        
        <?php if(count($users)): ?>
        
            <table>
                <thead>
                    <tr>
                        <th>Username</th>
                        <th>Email</th>
                        <th>Role</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach($users as $user): ?>
                        <tr>
                            <td><?php echo $user['username']; ?></td>
                            <td><?php echo $user['email']; ?></td>
                            <td><?php echo $user['role']; ?></td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        
        <?php else: ?>
        
            <div class="warning">
                Er zijn geen users gevonden in de database.
            </div>
        
        <?php endif; ?>
        
    </body>
</html>

Conclusie

Door eerst je functionele PHP code uit te voeren en daarna pas de output te versturen zal je code flexibeler zijn en beter leesbaar zijn. Bovendien heb je in de code nog de mogelijkheid om de http header aan te passen of voor een andere template te kiezen.

Reacties

Om een reactie te plaatsen kun je jezelf eenmalig registeren of je kunt hier inloggen.