logo oujood
🔍

Générer une page web dynamiquement avec PHP et la POO

Construisez une librairie de classes PHP réutilisable pour assembler des pages HTML morceau par morceau.

OUJOOD.COM

PHP cours tutorial

Générer une page web dynamiquement avec PHP et la POO

Ce tutoriel montre comment construire une librairie de classes PHP pour générer du HTML à la volée. Pas un framework, pas un moteur de templates — juste quelques classes qui s'assemblent pour produire une page HTML depuis du PHP pur.

L'exercice touche à quatre notions de la programmation orientée objet sur un problème concret : les classes, l'héritage, les classes abstraites et le pattern singleton.

Structure d'une page web

Avant d'écrire la moindre ligne de code, rappelons ce que contient une page web. Un document HTML suit toujours le même squelette : un doctype, une balise <html>, un entête <head> avec les métadonnées, et un corps <body> avec le contenu visible.

Ce squelette ne change pas d'une page à l'autre. Ce qui change, c'est le titre, la description, les fichiers CSS et JS chargés, et le contenu. C'est exactement ce que la librairie va prendre en charge.

La DTD et début de page

  📋 Copier le code

<!DOCTYPE html>
<html>

Entête (head)

  📋 Copier le code

<head>
  <title></title>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  <meta name="description" content="description de la page" />
  <meta name="keywords" content="mots clés" />
  <link href="monfichiercss.css" rel="stylesheet" type="text/css" />
  <script type="text/javascript" src="monfichierjs.js"></script>
</head>

Corps (body)

  📋 Copier le code

<body>
  // contenu de la page
</body>

Pied de page (footer)

  📋 Copier le code

<div>
</div>

Fermeture de la page

  📋 Copier le code

</body>
</html>

Un site web, ce sont des dizaines de pages qui partagent ce même squelette. Seul le contenu change. D'où l'idée de centraliser la génération de cette structure dans une librairie réutilisable plutôt que de la dupliquer partout.

Architecture de la librairie

La librairie repose sur trois classes. PageHTML orchestre tout : elle instancie Header et Corps, et produit le HTML final. Header gère le contenu de <head> — titre, description, mots-clés, fichiers CSS et JS. Corps accumule le contenu à afficher dans <body>.

On commence par la classe PageHTML dans sa forme la plus simple. Le constructeur est déclaré private — on verra pourquoi juste après :

  📋 Copier le code

// Classe principale de la librairie HTML
class PageHTML {
  // Constructeur privé — instanciation contrôlée via getInstance()
  private function __construct() {}
}

La classe PageHTML et le pattern Singleton

Une page HTML ne doit être générée qu'une seule fois par requête. Instancier PageHTML plusieurs fois n'aurait aucun sens — et gaspillerait de la mémoire serveur. Le pattern singleton règle ça directement.

La classe contrôle elle-même son instanciation. Elle stocke une référence à son unique objet dans une variable statique privée, et expose une méthode publique getInstance() qui retourne toujours ce même objet — qu'on l'appelle une fois ou cent fois dans le script.

Voici la méthode getInstance() isolée pour bien saisir la logique :

  📋 Copier le code

public static function getInstance() {
  if (!isset(self::$_instance)) {
    // Première fois : aucune instance n'existe, on la crée
    self::$_instance = new self;
  }
  // Dans tous les cas, on retourne la même référence
  return self::$_instance;
}

Voici la classe PageHTML complète, avec le singleton, les variables internes et l'instanciation de Header et Corps dans le constructeur :

  📋 Copier le code

<?php
require_once 'header.php';
require_once 'corps.php';

// Classe principale — un seul objet par requête (singleton)
class PageHTML {

  private static $_instance; // stocke l'unique référence
  private $_Corps;
  private $_header;

  public static function getInstance() {
    if (!isset(self::$_instance)) {
      self::$_instance = new PageHTML();
    }
    return self::$_instance;
  }

  // Constructeur privé : crée Header et Corps automatiquement
  private function __construct() {
    $this->_header = new Header();
    $this->_Corps  = new Corps();
  }

  public function getHeader() { return $this->_header; }
  public function getCorps()  { return $this->_Corps;  }

  // Assemble et retourne le HTML complet de la page
  public function getHTMLCode($print = false) {
    $sortie = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' . "\n"
      . '  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n"
      . '<html>'  . "\n"
      . $this->_header->getHeaderCode() . "\n"
      . $this->_Corps->getCorpsCode()   . "\n"
      . '</html>';
    if ($print) echo $sortie;
    return $sortie;
  }
}
?>

Pour utiliser cette classe dans un script PHP, une seule ligne suffit :

  📋 Copier le code

require_once 'lib/pagehtml.php';
// Récupère ou crée l'unique instance de PageHTML
$dochtml = PageHTML::getInstance();

La classe Corps

Corps construit ce qui va entre <body> et </body>. Son fonctionnement est volontairement minimaliste : une variable privée $_corpsCode accumule les morceaux de HTML ajoutés un à un via addCorpsElement(). getCorpsCode() retourne le tout encadré par les balises body.

  📋 Copier le code

<?php
class Corps {

  private $_corpsCode = ''; // contenu HTML du corps, vide par défaut

  // Ajoute un bloc HTML à la suite du corps
  public function addCorpsElement($corpselement) {
    $this->_corpsCode .= $corpselement;
  }

  // Retourne le corps complet encadré par <body></body>
  public function getCorpsCode() {
    return '<body>' . $this->_corpsCode . '</body>';
  }
}
?>

La classe Header

Header gère tout ce qui se trouve dans <head> : le titre, les balises meta (description, mots-clés, charset), les fichiers CSS et les fichiers JavaScript.

Chaque élément est stocké dans une variable privée avec sa valeur par défaut. Les setters permettent de les modifier depuis l'extérieur, les getters de les lire. Les fichiers CSS et JS sont délégués à deux classes spécialisées — CSS et JS — créées dans le constructeur.

Les variables internes de Header :

  📋 Copier le code

class Header {
  private $_charset     = 'utf-8';              // encodage par défaut
  private $_description = 'description du document';
  private $_keyWord     = 'mot cle';
  private $_title       = 'sans titre';
  private $_css; // instance de la classe CSS
  private $_js;  // instance de la classe JS
}

Les setters et getters pour chaque propriété suivent le même schéma :

  📋 Copier le code

// Setters — modifient la valeur stockée
public function setCharset($charSet)         { $this->_charset     = $charSet;     }
public function setDescription($description) { $this->_description = $description; }
public function setKeyWord($keyWord)         { $this->_keyWord     = $keyWord;     }
public function setTitle($title)             { $this->_title       = $title;       }

// Getters — retournent la valeur stockée
public function getCharset()     { return $this->_charset;     }
public function getDescription() { return $this->_description; }
public function getKeyWord()     { return $this->_keyWord;     }
public function getTitle()       { return $this->_title;       }

Le constructeur crée CSS et JS dès l'instanciation de Header. On peut donc leur ajouter des fichiers immédiatement, sans vérification préalable :

  📋 Copier le code

public function __construct() {
  $this->_css = new CSS(); // gestion des feuilles de style
  $this->_js  = new JS();  // gestion des fichiers JavaScript
}

Les classes JS, CSS et HeaderPart

Un document HTML peut charger plusieurs fichiers CSS et plusieurs fichiers JavaScript. Les classes CSS et JS gèrent chacune une liste de fichiers et produisent les balises HTML correspondantes : <link> pour CSS, <script> pour JS.

Ces deux classes font exactement la même chose — stocker des fichiers et produire du HTML. Seul le format de balise diffère. C'est le cas d'usage typique d'une classe abstraite : elle pose la structure commune et laisse aux classes filles ce qui varie. Ici, la méthode format() est abstraite — chaque classe fille l'implémente à sa façon.

Le code complet de la classe abstraite HeaderPart :

  📋 Copier le code

<?php
// Classe abstraite — parente de JS et CSS
abstract class HeaderPart {

  private $_src = array(); // liste des fichiers à inclure

  // Ajoute un fichier à la liste
  public function add($src) {
    $this->_src[] = $src;
  }

  // Abstraite : chaque classe fille définit sa propre balise HTML
  abstract protected function format($src);

  // Parcourt la liste et retourne toutes les balises générées
  public function getCode() {
    $sortie = '';
    foreach ($this->_src as $src) {
      $sortie .= $this->format($src) . "\n";
    }
    return $sortie;
  }
}
?>

La classe JS hérite de HeaderPart et implémente format() pour produire une balise <script> :

  📋 Copier le code

<?php
require_once 'headerpart.php';

// Hérite de add() et getCode() via HeaderPart
class JS extends HeaderPart {
  protected function format($src) {
    return '<script type="text/javascript" src="' . $src . '"></script>';
  }
}
?>

La classe CSS fait de même pour les feuilles de style :

  📋 Copier le code

<?php
require_once 'headerpart.php';

// Hérite de add() et getCode() via HeaderPart
class CSS extends HeaderPart {
  protected function format($src) {
    return '<link rel="stylesheet" type="text/css" href="' . $src . '" />';
  }
}
?>

On revient dans Header pour ajouter les méthodes qui permettent d'interagir avec CSS et JS sans y accéder directement, puis la méthode getHeaderCode() qui assemble le contenu de <head>. Voici le fichier Header.php final :

  📋 Copier le code

<?php
require_once 'js.php';
require_once 'css.php';

class Header {
  private $_charset     = 'utf-8';
  private $_description = 'description du document';
  private $_keyWord     = 'mot cle';
  private $_title       = 'sans titre';
  private $_css;
  private $_js;

  public function __construct() {
    $this->_css = new CSS();
    $this->_js  = new JS();
  }

  public function setCharset($charSet)         { $this->_charset     = $charSet;     }
  public function setDescription($description) { $this->_description = $description; }
  public function setKeyWord($keyWord)         { $this->_keyWord     = $keyWord;     }
  public function setTitle($title)             { $this->_title       = $title;       }
  public function getCharset()                 { return $this->_charset;             }
  public function getDescription()             { return $this->_description;         }
  public function getKeyWord()                 { return $this->_keyWord;             }
  public function getTitle()                   { return $this->_title;               }

  // Ajoute un fichier JS ou CSS à inclure dans le header
  public function addJSFile($jsfile)   { $this->_js->add($jsfile);   }
  public function addCSSFile($cssfile) { $this->_css->add($cssfile); }

  public function getJSCode()  { return $this->_js->getCode();  }
  public function getCSSCode() { return $this->_css->getCode(); }
  public function getJS()      { return $this->_js;              }
  public function getCSS()     { return $this->_css;             }

  // Retourne le HTML complet du <head>
  public function getHeaderCode($print = false) {
    return '<head>' . "\n"
      . '<title>'  . $this->getTitle()       . '</title>'  . "\n"
      . '<meta http-equiv="Content-Type" content="text/html; charset='
      . $this->getCharset() . '">' . "\n"
      . '<meta name="description" content="' . $this->getDescription() . '" />' . "\n"
      . '<meta name="keywords"    content="' . $this->getKeyWord()     . '" />' . "\n"
      . $this->getCSS()->getCode() . "\n"
      . $this->getJS()->getCode()  . "\n"
      . '</head>' . "\n";
  }
}
?>

Test de la librairie

On place tous les fichiers dans un dossier lib/, puis on crée un fichier index.php. Le script récupère l'instance de PageHTML, configure le header, ajoute du contenu dans le corps, et affiche le HTML généré :

  📋 Copier le code

<?php
require_once 'lib/pagehtml.php';

$page = PageHTML::getInstance();

// Configuration du header
$page->getHeader()->setTitle('Page de test');
$page->getHeader()->setDescription('Nouvelle description');
$page->getHeader()->setKeyWord('mot1, mot2');
$page->getHeader()->addCSSFile('style.css');

// Ajout du contenu dans le corps
$page->getCorps()->addCorpsElement('<p>Test de la librairie HTML</p>');
$page->getCorps()->addCorpsElement('<a href="https://www.oujood.com/">Retour à Oujood</a>');

echo $page->getHTMLCode();
?>

Un fichier style.css minimal pour vérifier que le chargement fonctionne :

  📋 Copier le code

body { background-color: #000000; }
p    { font-family: arial; font-size: 50px; color: #FFFFFF; }
a    { text-decoration: none; color: #FFFF00; }

La librairie reste volontairement simple — c'est son intérêt pédagogique. Elle ne remplace pas un framework PHP, mais montre comment la POO découpe un problème concret en responsabilités claires. Si vous voulez aller plus loin, deux pistes : la gestion des balises <meta og:> pour les réseaux sociaux, ou un système de templates pour le corps.

Par carabde | Mis à jour le 12 mai 2026