Du är här: keryx/artikel/47. Hoppa till huvudinnehållet (h) Sidans menysektion:
Keryx logotype

Vägen till tre skikt

Om denna artikel

Presentation av flerkskiktsarkitektur för ovana PHP-utvecklare.

Publicerad: 2006-09-21

Uppdaterad: 2006-09-21

 

Samtliga böcker - och nästan alla hemsidor - som behandlar PHP på svenska lär dig dålig kodning. Ett av problemen är att man inte skiljer mellan presentationslogik, affärslogik och dataaccesslogik.

Ta följande exempel (som kunde varit hämtat ur en bok av Jesper Ek): Du har en anslutning till mysql (eftersom du läst en dålig sida/bok så är det PHP 4 mysql-funktionerna vi pratar om). Du vill hämta topp 5 filmerna i din databas och skriva ut resultatet som en tabell.

Dåligt exempel


$sql = "SELECT titel,årtal,rank FROM filmer ORDER BY rank DESC LIMIT 0,5";

$svar = mysql_query($sql)
  or die("Inget felmeddelande som kan hjälpa en hacker")

echo "<table>\n<tr>\n";
echo "<th>Titel</th><th>Årtal</th><th>Rankning</th>\n";
echo "</tr>\n";

while ( $rad = mysql_fetch_assoc($svar) ) {
    echo "<tr>\n";
    echo "<td>{$rad['titel']}</td>\n";
    echo "<td>{$rad['årtal']}</td>\n";
    echo "<td>{$rad['rank']}</td>\n";
    echo "<tr>\n";
}
echo "</table>\n";

Detta kan tyckas oskyldigt, men så fort du börjar lägga in lite mer avancerade kontroller av dataintegritet (affärslogik), fler attribut i HTML-koden (presentationslogik) så blir det grötigt, svårt att uppdatera och allmänt svårt att hantera. Skulle du i framtiden vilja byta databashanterare så måste du skriva om alltihop. Byter du från mysql-funktionerna till mysqli- funktionerna så har du databasanrop lite överallt att leta reda på och ändra på.

I största möjliga mån bör man sträva efter att isolera kod som hanterar kontakten med lagrad data, kod som bearbetar inhämtad data och kod som presenterar densamma. Professionell programmering är (anser jag) objektorienterad, men redan i procedurell kod kan man börja renodla sin struktur.

Ett bättre exempel

Först av allt så byter vi till PDO för att sköta kontakten med databasen. Detta är en tekniskt överlägsen lösning och möjliggör en mångfald förbättringar på sikt.

Följande kod bör finnas i en fil med övergripande inställningar (rakt av ur manualen):


$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';

try {
   $dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
   // Hantera felet här på lämpligt sätt
}

Du har nu en global variabel med kopplingen till databasen. Helst bör man lagra denna variabel i ett registry-objekt, men det är inte ämnet för denna artikel.

Nästa steg, unikt för din aktuella fil. Hämta data ur databasen.


$sth = $dbh->prepare("SELECT titel,årtal,rank FROM filmer ORDER BY rank DESC LIMIT 0,5");
$sth->execute();

Flytta in all data i en array:


$filmdata = $sth->fetchAll();
När du är klar med PDO-objektet, så tag bort det ur minnet:

unset($dbh);

Vi är nu klara med data-access-logiken. Dags att bearbeta data. För detta exempel så lämnar jag dock det därhän. Vi förutsätter att hämtade data är OK. I verkligheten skulle vi behöva göra vissa integritetskontroller och/eller "eskejpa" vår data så att den kan visas som en del av vår sida. (Filter input, escape output.) Sådan "eskejpning" är en av de saker som kan tillkomma och göra PHP-koden oerhört grötig, om man blandar hämtning, bearbetning och visning av sin data huller om buller. Genom att affärslogiken är separat så slipper vi alltsp detta.

Dags för presentationslogiken. Här finns det två skolor: Pull och Push. Antingen så har man en mall från vilken php-variabler hämtas in, eller så skickas variablerna till mallen uttryckligen.

Enkla mallar kan göras direkt i PHP, men de bör vara lagrade i egna filer, som kan återanvändas av flera olika sidor, eller som kan uppdateras av någon annan.

Om du har redigerat en mall för blogger eller liknande så förstår du konceptet. Om du gör mallar direkt i PHP så är det smart att undvika måsvingarna för gruppering och i stället använda syntaxen med kolon. Heredoc-syntax är också mycket användbar.

Utdrag ur mallen:


echo <<<TABSTART
<table>
  <tr>
    <th>Titel</th><th>Årtal</th><th>Rankning</th>
  </tr>
TABSTART;

// OBS! Kolon - inte måsvinge
foreach ( $filmdata as $film ): echo <<<RAD
  <tr>
    <td>{$film['titel']}</td>
    <td>{$film['årtal']}</td>
    <td>{$film['rank']}</td>
  <tr>
RAD;
endforeach; // motsvarar slut-måsvingen

echo <<<TABSLUT
</table>
TABSLUT;

Det sista användandet av heredoc var kanske onödigt, men det lönar sig oftast att vara konsekvent.

En fördel med att inte använda måsvingarna är att man kan hoppa in och ut ur php-läge utan att det blir svårt att följa logiken. Då ser mallen ut så här:


<table>
  <tr>
    <th>Titel</th><th>Årtal</th><th>Rankning</th>
  </tr>
<?php foreach ( $filmdata as $film ): ?>
  <tr>
    <td><?php echo $film['titel']; ?></td>
    <td><?php echo $film['årtal']; ?></td>
    <td><?php echo $film['rank']; ?></td>
  <tr>
<?php endforeach; ?>
</table>

Ett ytterligare exempel på denna måsvingefria syntax finns på adressen rhymedcode.net/1001-wordpression-loops/grouped-by-category/

Sidans övergripande kontrollerskript ser alltså ut så här schematiskt:

  1. Hämta filen som initierar DBO
  2. Utför databasanrop och lagra resultatet i en array
  3. Bearbeta resultat (ej nödvändigt i exemplet ovan)
  4. Inkludera mallen - som i detta exempel också är en PHP-fil

Framtiden

När du växer i kunnande så kan du lämpligen börja med att låta de första och sista stegen ske objektbaserat, och kanske dessutom lagra resultatet som hämtats ur databasen som ett objekt i stället för en array, för att låta kontroller av dataintegritet och bearbetning av data ligga inuti objektet som sådant. Det objektet kan i sin tur cachas och/eller skrivas så att du utnyttjar en koppling till databasresultatet så att mellanlagringen i en array inte längre behövs. När man slutar att använda de gamla mysql-metoderna och övergår till PDO eller MDB2

Om affärslogiken till stor del flyttas in i dataobjekten, så återstår snart bara ett mycket kort procedurellt skript på sidan som kontrollerar kontrollerar själva sidvisningen. Tanken på separat kod för dataåtkomst (model), separata mallar för att generera HTML-koden (view) i kombination med ett sådant kontroll-skript (controler) har gett upphov till designmönstret MVC.

Din utveckling som PHP-utvecklare

Att gå från statiska hemsidor med vissa inslag av PHP-kod, över till helt dynamiska sidor är ditt första utvecklingssteg. Vad jag vill uppmuntra till i denna artikel är att du redan vid denna övergång börjar skilja ut kod som hämtar från och lämnar data till datalagringen, från kod som bearbetar data och från kod som visar resultatet.

Ditt nästa steg är att använda enklare objekt. Objektbaserad programmering blir då ett övergångssteg till objektorienterad dito. Med model-view.controler som övergripande designmönster (eng: patterns) kan du sedan börja förbättra din kod, designmönster för designmönster.

Lär dig mer

Börja med att läsa en bra bok om PHP. Kolla in vad Harry Fuecks skriver på Sitepoint. Kolla in artiklar som den här på Zend. Men vad du än gör - läs inget mer om PHP som skrivits av Jesper Ek...

Efterskrift

Jag skulle kunna använt syntaxen


<?= $foo ?>

i stället för


<?php echo $foo; ?>

Detta kräver att man tillåter KORTA öppningstaggar, vilket inte är att rekommendera.

Artikelinfo
Publicerad:2006-09-21 17:18     Författare:itpastorn
Uppdaterad:2006-09-21 17:18     Ämne:Php
Uppdaterad: 2006-09-21 17:18    © Keryx