Separare il markup dal codice PHP

Ho avuto la necessità di realizzare un sito parzialmente statico, ovvero con contenuti statici e una leggera base programmativa. Uno dei problemi che ho cercato di risolvere è stato quello di separare quanto più possibile la parte di scripting dal contenuto html, tecnicamente parlando, separando il markup dalla logica. Questo per poter gestire il codice: a breve termine, dando modo al programmatore e al webdesigner di lavorare indipendentemente, e a lungo termine, per facilitare il riuso del codice (HTML e PHP) e la sua manutenibilità.
Il linguaggio scelto è PHP, uno dei linguaggi di scripting per il web più diffusi. Nelle varie soluzioni che qui riprenderò valuterò vari aspetti della stessa, con il chiaro scopo di cercare di realizzare un codice che fosse il più semplice possibie, e utilizzare l'OOP il meno possibile.

La base di partenza

Chiunque abbia provato a lavorare con PHP ha sicuramente lavorato con print e echo, quindi la situazione di partenza è proprio quella in cui il codice è frammisto a pezzi di HTML, il classico macello programmativo.

index.php

<?php
// funzioni di vario genere
// inizializzazioni di variabili
// if vari ed eventuali
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ...
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<title>
<?php
if ($_GET['page']=="sect1") echo "Sezione 1 del mio sito";
else echo "Il mio primo sito";
 ?>
	</title>
</head>
<body>
	<div id="menu"><a href="?page=sect1">Sezione 1</a></div>
	<div id="content">
<?php
if ($_GET['page']=="sect1") echo "<h1>Prova</h1><p>questa è una prova</p>";
else echo "<h1>Benvenuti</h1><p>Questa è la home page</p>";
?>
	</div>
</body>
</html>

Faccio presente la differenza dell'uso dei " (doppi apici) e degli ' (apici singoli): con i doppi apici non occorre usare la concatenazione delle stringhe in quanto permetterà di valorizzare automaticamente le variabili (denotate da $). Questo invero non avviene se cercate di usare degli array.
Il codice sopra descritto di solito porta alla pazzia, specialmente quando il numero di righe inizia a superare il 500~1000.
Da buoni (?) programmatori allora proviamo a togliere il codice HTML dalla logica utilizzando una funzione stupenda che si chiama include() (la si trova invero perché una ricerca nel manuale online di php porta inesorabilmente lì).

Usare include()

La cosa interessante di include, è che funziona come una sostituzione letterale della riga di include() con il contenuto del file specificato, prima che lo script venga interpretato, consentendoci quindi di scrivere codice nel file incluso (altre variazioni della funzione sono require(), include_once() e require_once()). Quindi ci troveremo con la logica

index.php

<?php
// funzioni di vario genere
// inizializzazioni di variabili
if ($_GET["page"]=="sect1") $title = "Sezione 1 del mio sito";
else $title = "Il mio primo sito";
// if vari ed eventuali
include("markup.php");
?>

e il markup:

markup.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ...
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<title>
<?php echo $title; ?>
	</title>
</head>
<body>
	<div id="menu"><a href="?page=sect1">Sezione 1</a></div>
	<div id="content">
<?php
if ($_GET['page']=="sect1") echo "<h1>Prova</h1><p>questa è una prova</p>";
else echo "<h1>Benvenuti</h1><p>Questa è la home page</p>";
?>
	</div>
</body>
</html>

Sicuramente si può procere all'infinito in questa maniera, riducendo magari l'unica stringa php del markup in:

markup.php

...
<?php
if ($_GET['page']=="sect1") include("sect1.html");
else include("home.html");
?>
...

ed infine il vero e proprio contenuto:

sect1.html

<h1>Prova</h1>
<p>questa è una prova</p>

home.html

<h1>Benvenuti</h1>
<p>Questa è la home page</p>

Includere manualmente?

L'unica debolezza di include è però la necessità di espandere ed interpretare il codice da includere, che influisce all'aumentare del volume delle pagine. L'alternativa è usarlo solo dove serve.

index.php

<?php
// funzioni di vario genere
function fileRead($filename)
{
	$fileContent = "";
	if ($file = fopen($filename, 'r')) 
	{
		$fileContent = fread($file, filesize($filename));
		fclose($file);
	}
	return $fileContent;
}
// inizializzazioni di variabili
// $page conterrà "markup.php" come stringa di testo
$page = fileRead("markup.php");
if ($_GET['page']=="sect1")
{
	str_replace("{TITLE}", "Sezione 1 del mio sito", $page);
	str_replace("{CONTENT}", fileRead("sect1.html"), $page);
}
else
{
	str_replace("{TITLE}", "Il mio primo sito", $page);
	str_replace("{CONTENT}", fileRead("home.html"), $page);
}
echo $page;
?>

dove markup.html avrà mantenuto una compatezza che ci consentirà una modifica immediata del codice html senza paura di aver dimenticato un tag aperto (o chiuso).

markup.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ...
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<title>{TITLE}</title>
</head>
<body>
	<div id="menu"><a href="?page=sect1">Sezione 1</a></div>
	<div id="content">
		{CONTENT}
	</div>
</body>
</html>

Il senso di usare {QUALCOSA} come stringa da sostituire è solo per avere un elemento unico e distinguibile immediatamente alla funzione di ricerca stringhe str_replace().
Questa infatti non è altro che una soluzione idiota ad un problema ben più grosso.

Smarty PHP Templating Library

Smarty è una libreria che mi ha ispirato per realizzare l'esempio precedente, ma consente la realizzazione di logiche complesse, come la possibilità di ripetere porzioni codice di markup, ad es. per realizzare un template per un blog, i cui post si ripetono (come codice HTML) nella pagina: quindi scrivendo un solo blocco e definire degli array su cui iterare.

index.php

<?php // funzioni di vario genere
// inizializzazioni di variabili
// if vari ed eventuali
$smarty_site = new Smarty_Site();
if ($_GET['page']=="sect1")
{
	$title = "Sezione 1 del mio sito";
	$content = "sect1.html"
}	
else
{
	$title = "Il mio primo sito";
	$content = "home.html";
}
$smarty_site->assign("title", $title);
$smarty_site->assign("content", $content);
$smarty_site->display("markup.tpl");
?>

Con home.html e sect1.html che rimangono così come li abbiamo definiti, mentre markup.tpl sarà:

smarty/templates/markup.tpl

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ...
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<title>{$title}</title>
</head>
<body>
	<div id="menu"><a href="?page=sect1">Sezione 1</a></div>
	<div id="content">
		{include file=$content}
	</div>
</body>
</html>

Tutti i file saranno messi nella directory templates in base alle direttive della libreria.
Chiaramente l'esempio non sfrutta le potenzialità di Smarty, qundi una buona letta alla sua documentazione potrebbe aiutare!

Usare eval()

Un'altra possibilità di templating che è possibile realizzare con PHP è quella di sfruttare le potenzialità della funzione eval(): questa funzione non fa altro che valutare come codice il contenuto di una stringa. L'esempio è tratto direttamente dal sito di php.net.

<?php
function parseTemplate($template, $params=array()) {
	foreach ($params as $k=>$v) {
		$$k = $v;
	}
	ob_start();
	eval("?>" . implode("", file($template)) . "<?");
	$c = ob_get_contents();
	ob_end_flush();
	return $c;
}
?>

Nota: ob_start(), ob_get_contents(), ob_end_flush(), servono per bufferizzare, cioè ritardare l'output che eval produrebbe, consentendoci quindi di salvarlo nella variabile $c che verrà quindi ritornata.
Esempio:
<?php
echo parseTemplate("myTemplate.php", array('account'=>$row));
?>

e myTemplate.php:
<?php foreach($account as $k=>$v) : ?>
  <?=$k?>: <?=$v?>
<? endforeach; ?>

Conclusioni

Col fatto che php è stra-usato, di metodi applicativi ce ne sono a bizzeffe: quello che importa è capire il sistema di funzionamento del programma, quindi come sfruttarlo al meglio. I vari metodi presentati hanno una complessità sempre maggiore, per cui gli ultimi due esempi necessitano un minimo di basi dell'uso degli oggetti (in php4 e php5) e degli array associativi.

Spero non vi siate annoiati ;-)

Torna su

I discovered your blog site

I discovered your blog site on google and examine a couple of of your early posts. Continue to keep up the very good operate. I simply extra up your RSS feed to my MSN Information Reader. Seeking forward to studying more from you afterward!...
best memory foam mattress

Zend?

Ue.. chi si rilegge!

La separazione del codice di markup e' sempre stata una mia fissa.
Pensa... per un sito tipico su LAMP.

Linguaggio di programmazione PHP che genera linguaggio di Ipertesto, recuperando informazioni con un linguaggio di interrogazione. (SQL). (non menziono neanche Javascript dentro l'html)

Un gran casino... indubbiamente.

Io ho trovato un buon compromesso con ZEND, dopo aver provato Smarty in modo molto superficiale.

Zend Framework e' molto flessibile e dopo un po' che lo si usa tutto diventa piu' semplice. (e gestibile)

Con Zend hai dei controllers che impostano delle view, utilizzando dei Modelli per il DB.

Ti consiglio di dargli un occhio :)
A presto ;)

Ciao

Bello leggerti

ciao XChris, bello leggerti.
In ogni caso hai ragione, Zend è un framework per PHP molto potente che merita davvero il suo uso.
Potrebbe cmq risultare un pelo troppo per chi desidera fare cose piccoline :)

ottimo suggerimento anyway

Classe per il layout delle pagine

Ciao,

interessante l'articolo. Se ti appassiona l'argomento anche io avevo fatto una mia classe per separare completamente il layout dalla logica di business: ecco il link.

Logicamente per fare ciò devi eliminare i cicli e via dicendo, ma ritengo che alla fine il gioco valga la candela.

Ciao e buon lavoro. Nicola

gain

io non mi sono annoiato, l'ho trovato interessante! ;)

ps: se clicco su "Aggiungi commento" mi si apre un'altra pagina; inoltre, nell'inserimento del commento, non c'è la possibilità di inserire il proprio nome, ma solo un eventuale titolo e il commento stesso... :|

Grazie mille per la

Grazie mille per la segnalazione, ho aggiunto l'obbligo di inserimento nome :)
(sono quelle due o tre cosette che mancano da sistemare ;) )

Invia nuovo commento

Il contenuto di questo campo è privato e non verrà mostrato pubblicamente.
  • Indirizzi web o e-mail vengono trasformati in link automaticamente
  • Elementi HTML permessi: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <acronym> <h2> <h3> <h4> <h5> <h6> <img> <pre> <span>
  • Linee e paragrafi vanno a capo automaticamente.
  • Puoi abilitare l'evidenziazione della sintassi del codice sorgente usando i seguenti tag: <code>, <blockcode>. The supported tag styles are: <foo>, [foo].
  • Images can be added to this post.

Maggiori informazioni sulle opzioni di formattazione.

CAPTCHA
Se sei qui per dello SPAM hai sbagliato tutto della vita.

Site optimized for Gecko and Webkit browsers - Copyright © 2008 - Matteo 'Peach' Pescarin