Je lisais cette question sur stackoverflow:
https://stackoverflow.com/questions/104516/calling-php-functions-within-heredoc-strings
et la réponse acceptée dit de faire des modèles simples PHP comme ceci:
template.php:
<html> <head> <title><?=$title?> </title> </head> <body> <? = getContent ()?> </body> </html>
index.php:
<? php $ title = 'Titre de démonstration'; fonction getContent () { return '<p> Bonjour tout le monde! </p> '; } comprennent (' template.php '); ?>
Pour moi, ce qui précède n'est pas bien structuré dans le sens où template.php dépend de variables définies dans d'autres scripts. Et vous utilisez un include () pour exécuter du code lorsque vous faites include('template.php')
(par opposition à utiliser include () pour inclure une classe ou une fonction qui n'est pas immédiatement exécutée).
Je pense qu'une meilleure approche consiste à envelopper votre modèle dans une fonction:
template.php:
<? php modèle de fonction ($ title, $ content) { ob_start (); ?> <html> <head> <title><?=$title?> </title> </ head > <body> <? = $ content?> </body> </html> < ? php return ob_get_clean (); } ?>
index.php:
<? php require_once ('template.php'); modèle d'impression ('Demo Title', '<p> Hello World! </ p > '); ?>
La deuxième approche est-elle meilleure? Existe-t-il une meilleure façon de procéder?
Je ne ferais pas la deuxième approche car les paramètres ne sont pas nommés.
Un bien écrit essai sur la description du fonctionnement d'un système de modèles devrait fonctionner provient de Parr, il est souvent cité par des personnes écrivant des systèmes de modèles et/ou des frameworks web-mvc.
Personnellement, je préfère généralement implémenter une classe ArrayObject avec un tableau de propriétés, et le modèle ferait référence à $this->propertyName
, Qui serait en fait le $this->property['name']
De l'objet modèle. Cela pourrait également être réalisé simplement en utilisant __set
Et __get
, Donc:
class Template {
private $_scriptPath=TEMPLATE_PATH;//comes from config.php
public $properties;
public function setScriptPath($scriptPath){
$this->_scriptPath=$scriptPath;
}
public function __construct(){
$this->properties = array();
}
public function render($filename){
ob_start();
if(file_exists($this->_scriptPath.$filename)){
include($this->_scriptPath.$filename);
} else throw new TemplateNotFoundException();
return ob_get_clean();
}
public function __set($k, $v){
$this->properties[$k] = $v;
}
public function __get($k){
return $this->properties[$k];
}
}
et un modèle ressemblerait à:
<html>
<head>
<title><?=$this->title?></title>
</head>
<body>Hey <?=$this->name?></body>
</html>
et l'invoquer ressemblerait à:
$view = new Template();
$view->title="Hello World app";
$view->properties['name'] = "Jude";
echo $view->render('hello.inc');
Pour autant que je m'en souvienne, c'est à quoi ressemblent les anciens Symfony 1.x et les moteurs de modèles Zend_View, et pour moi ça va.
Parce que Codeigniter est mon framework préféré, je vous propose une solution Codeigniter-ish:
class Template {
protected $path, $data;
public function __construct($path, $data = array()) {
$this->path = $path;
$this->data = $data;
}
public function render() {
if(file_exists($this->path)){
//Extracts vars to current view scope
extract($this->data);
//Starts output buffering
ob_start();
//Includes contents
include $this->path;
$buffer = ob_get_contents();
@ob_end_clean();
//Returns output buffer
return $buffer;
} else {
//Throws exception
}
}
}
Votre modèle ressemblerait à:
<html>
<head>
<title><?=$title?></title>
</head>
<body>
<?=$content?>
</body>
</html>
Et vous le rendriez en instanciant la classe, en passant des données dans un tableau en tant que paramètre constructeur et en appelant la méthode 'render':
$data = array('title' => 'My title', 'content' => 'My content');
$tmpl = new Template('template.php', $data);
echo $tmpl->render();
De cette façon, vous n'exécutez pas directement le code inclus et vous gardez également votre modèle lisible, donc les concepteurs seront heureux.
La première template.php
est plus facile à charger tel quel dans dreamweaver/bluegriffon/que ce soit et édité par un concepteur Web non averti côté serveur, le second ... eh bien, il pourrait toujours, mais c'est beaucoup plus susceptible de se casser pendant le processus d'édition.
J'irais avec le premier pour qu'il ressemble à HTML avec des avantages, la façon dont les concepteurs tiers préfèrent généralement.
Un modèle toujours dépendra de variables externes, et avec PHP étant un langage dynamique, il n'y a aucun moyen de faire respecter lors de la compilation qu'elles seront là. la première approche est probablement très bien, mais il y a encore quelques problèmes:
Une approche très simple consiste à écrire une fonction, de préférence avec un nom très court, qui prend en charge les deux; l'appeler _()
semble être une convention courante. Une version simple pourrait ressembler à ceci:
function _($raw) {
if (isset($raw)) {
return htmlspecialchars($raw);
}
}
Et puis dans votre modèle, vous feriez:
<title><?= _($title) ?></title>
Plus de choses à faire avec la fonction _()
:
htmlspecialchars
, dans les cas où vous souhaitez lui passer du code HTML plutôt que des chaînes brutes.Array
et Object
, mais plutôt quelque chose de significatif (ou chaîne vide).