[Qu'est-ce que MVC ? 】
MVC est un concept qui vous permet de combiner harmonieusement « trois parties (à savoir le nom complet de MVC, le modèle, la vue et le contrôleur) » pour former une application complexe. Une voiture est un très bon exemple de MVC dans la vraie vie. Lorsque nous regardons une voiture, nous regardons deux parties de vue (affichage) : l'intérieur et l'extérieur. Ces deux éléments sont indissociables d’un Contrôleur : le pilote. Le système de freinage, le volant et les autres systèmes de contrôle représentent le modèle : ils reprennent les méthodes de contrôle du conducteur (Controller) et les appliquent à l'intérieur et à l'extérieur (View).
[MVC sur le Web]
Les concepts couverts par le framework MVC sont assez simples et extrêmement flexibles. Le concept de base est que vous disposez d'un seul contrôleur (tel que index.php) qui contrôle toutes les applications du framework basées sur des requêtes de paramètres. Ce contrôleur contient généralement (au minimum) un paramètre qui définit le modèle, un événement et un paramètre GET. De cette façon, le contrôleur peut accuser réception de toutes les demandes et exécuter les événements appropriés. Par exemple, une requête comme celle-ci /index.php?module=foo&event=bar est probablement utilisée pour charger une classe nommée foo, puis exécuter foo::bar()[qui est la fonction bar()]. Les avantages de ceci sont les suivants :
maintenir une interface pour toutes les applications
tout en conservant d'innombrables codes dans une application est très gênant, car chaque morceau de code a son propre chemin relatif, lien de base de données, vérification, etc. Cela vous évite des problèmes et vous permet de fusionner et de réutiliser du code
[Pourquoi créer votre propre framework MVC ? 】
Jusqu'à présent, je n'ai pas vu beaucoup de frameworks MVC écrits en PHP. En fait, je n'en connais qu'un - Solar, qui est entièrement écrit en PHP5. L'autre est Cake, qui tente d'être RoR (Ruby on Rails - un framework réseau open source pour le langage Ruby) de PHP. J'ai moi-même une certaine insatisfaction avec les deux frameworks : ils ne profitent pas du code existant inclus dans PEAR, Smarty, etc. ; le Cake actuel est encore relativement brouillon ; enfin, Solar est un framework écrit principalement par une seule personne (j'ai. aucune intention de dire que son auteur, Paul, n'est ni une bonne personne ni un bon programmeur). Ces questions ne vous incitent probablement pas à les nier, et il y a de fortes chances que vous ne vous en souciiez pas du tout. Mais c’est pour cette raison que je vous demande de les examiner autant que possible.
[Ancienne méthode]
Si vous revenez à 2001 et regardez le code que vous avez écrit, l'auteur peut trouver un fichier appelé template.txt, qui ressemble à ceci : www.phpv.net Veuillez indiquer la source de la réimpression
<?php
require_once('config.php'); // Autres exigences, informations sur la base de données, etc.
$APP_DB = 'mydb';
$APP_REQUIRE_LOGIN = false ; // Défini sur true si le script nécessite une connexion
$APP_TEMPLATE_FILE = 'foo.php'; // Modèle intelligent
$APP_TITLE = 'Mon application';
if ($APP_REQUIRE_LOGIN == true) {
if (!isset($_SESSION['userID'])) {
header("Emplacement : /chemin/vers/login.php");
sortie();
}
}
$db = DB::connect('mysql://'.$DB_USER.':'.$DB_PASS.'@localhost/'.$APP_DB);
si (!PEAR::isError($db)) {
$db->setFetchMode(DB_FETCHMODE_ASSOC);
} autre {
mourir($db->getMessage());
}
// Mettez votre logique ici
// Affiche le modèle
include_once(APP_TEMPLATE_PATH.'/header.php');
include_once(APP_TEMPLATE_PATH.'/'.$APP_TEMPLATE_FILE);
include_once(APP_TEMPLATE_PATH.'/footer.php');
?>
Oh mon Dieu, rien que de regarder ce code me fait grincer des dents. Le concept de ce code est de garantir que chaque application peut être adaptée à cette méthode de traitement. Par exemple, je peux simplement copier template.txt dans myapp.php, modifier quelques variables, et le tour est joué. Néanmoins, cette approche très organisée présente de sérieux inconvénients : et
si mon patron voulait que l'auteur utilise myapp.php pour produire des fichiers PDF dans certains cas, HTML dans certains cas et SOAP dans certains cas (requêtes XML soumises directement), que dois-je faire ? faire?
Que dois-je faire si cette application nécessite une authentification IMAP ou LDAP ?
Comment gérer les différents types de code (y compris les modifications, les mises à niveau et les suppressions) ?
Comment gérer l'authentification à plusieurs niveaux (administrateur ou non-administrateur) ?
Comment activer la mise en cache de sortie ? www.phpv.net Veuillez indiquer la source de réimpression
[Nouvelle façon]
Jetez tout dans ce framework MVC, et vous constaterez que la vie est si simple. Veuillez comparer le code suivant :
<?php
la classe myapp étend FR_Auth_User
{
fonction publique __construct()
{
parent::__construct();
}
fonction publique __default()
{
// Fais quelque chose ici
}
fonction publique delete()
{ }
fonction publique __destruct()
{
parent::__destruct();
}
}
?>
Notez que ce code n'est évidemment pas utilisé pour créer un lien vers une base de données, déterminer si un utilisateur est connecté ou afficher toute autre information. Le contrôleur a tout.
Si je souhaite m'authentifier auprès de LDAP, je peux établir FR_Auth_LDAP. Le contrôleur peut reconnaître certaines méthodes de sortie (telles que $_GET['output']) et peut convertir en PDF ou SOAP à tout moment. Le gestionnaire d'événements delete est uniquement responsable de la suppression et ne se soucie de rien d'autre. Parce que ce module possède une instance de la classe FR_User, il peut simplement déterminer si un utilisateur est connecté, etc. Smarty, en tant que moteur de template, contrôle naturellement le cache, mais le contrôleur peut également contrôler une partie du cache.
Passer de l'ancienne méthode mentionnée précédemment à la méthode MVC peut être un concept nouveau et peu familier pour de nombreuses personnes, mais une fois que vous aurez adopté un tel concept, il sera assez difficile de revenir en arrière.
[Construire la couche inférieure]
Je suis un fan de PEAR, en particulier de la classe PEAR_Error. PHP5 introduit une nouvelle classe intégrée "Exception" qui remplace PEAR_Error. Mais PEAR_Error possède des fonctionnalités plus pratiques que Exception. Par conséquent, les exemples de framework MVC de cette série d’articles l’utiliseront pour la gestion des erreurs. Quoi qu'il en soit, je dois toujours utiliser Exception pour obtenir l'erreur du constructeur, car ils ne peuvent pas renvoyer l'erreur eux-mêmes.
Le but de la conception de ces classes de base est le suivant :
Utilisez PEAR pour ajouter rapidement des fonctions aux classes de base
afin de créer de petites classes abstraites pratiques à plusieurs reprises afin que les utilisateurs puissent développer rapidement des applications dans ce cadre.
Utilisez phpDocumentor pour générer des documents pour toutes les classes de base
. La hiérarchie des classes ressemblera à ceci :
- FR_Object fournira des fonctionnalités de base pour tous les autres objets à utiliser (y compris la journalisation, setFrom() général, toArray())
- FR_Object_DB est une petite couche qui fournit des liens de base de données vers des sous-classes et d'autres fonctions
- FR_Module est la classe inférieure de toutes les applications (également appelées modules, modèles, etc.)
- FR_Auth est la classe inférieure de tous les mécanismes de vérification
· FR_Auth_User est une classe de vérification utilisée pour vérifier tous les modules qui doivent vérifier si l'utilisateur est connecté
· FR_Auth_No est toutes les "fausses classes de validation" pour les modules qui ne nécessitent pas de validation
- FR_Presenter est la classe sous-jacente pour toutes les applications qui gèrent le chargement et l'affichage
- FR_Presenter_Smarty est la couche de présentation qui inclut la possibilité de charger différents lecteurs. Smarty est une très bonne classe de modèles. Elle possède un mécanisme de mise en cache intégré et un groupe de développement actif (Note du traducteur : il s'agit évidemment d'une publicité ~)
· FR_Presenter_debug est la couche d'affichage de la partie débogage. En s'appuyant sur lui, les développeurs peuvent déboguer les applications et les déboguer
. FR_Presenter_rest est une couche de présentation REST qui permet aux développeurs de générer des applications en XML.
À partir de la structure de classe de base ci-dessus, vous devriez pouvoir voir les différentes parties de ce framework MVC. FR_Module fournit tout ce dont le module a besoin, tandis que FR_Presenter propose différentes méthodes d'affichage. Dans le prochain article de cette série, je créerai un contrôleur qui relie toutes les classes de base ci-dessus.
[Normes de codage]
Avant d'écrire formellement du code, vous devez vous asseoir et discuter (ou réfléchir) aux normes de codage avec vos partenaires (ou vous-même). L'idée générale de la programmation MVC s'articule autour de deux points : la réutilisabilité du code (réduction des coïncidences) et la standardisation du code. Je recommande au moins de prendre en compte les points suivants :
La première chose à considérer concerne les normes de dénomination et d'abréviation des variables. Ne vous lancez pas dans une grosse bagarre avec vos partenaires à cause de cela, mais une fois les normes fixées, elles doivent être respectées du début à la fin, notamment lors de l'écriture de code de bas niveau (classes de base).
Personnalisez un préfixe standard à utiliser sur toutes les fonctions, classes et variables globales. Malheureusement, PHP ne prend pas en charge "l'espace de noms (espace de noms)". Ainsi, pour éviter toute confusion et tout conflit avec les noms de variables, il est judicieux d'utiliser un préfixe. J'utiliserai "FR_" comme préfixe tout au long de cet article.
[Écrire la couche inférieure]
La planification au niveau des fichiers est très importante. La planification hiérarchique de base est simple et quelque peu étroitement définie :
/
config.php
index.php
comprend/
Auth.php
Authentification/
N°.php
Utilisateur.php
Module.php
Objet.php
Objet/
DB.php
Présentateur.php
Présentateur/
commun.php
débogage.php
smarty.php
Intelligent/
module/
exemple/
config.php
exemple.php
tpl/
exemple.tpl
tpl/
défaut/
cache/
configuration/
modèles/
templates_c/
Vous pourriez penser qu'une telle hiérarchie de fichiers doit représenter beaucoup de code ! C'est vrai, mais vous pouvez y parvenir. À la fin de la série, vous constaterez que votre programmation deviendra plus facile et que votre vitesse de développement sera grandement améliorée.
Dans la hiérarchie des fichiers, toutes les classes de base se trouvent dans le dossier include. Chaque module fonctionnel utilise un fichier de configuration, au moins un fichier de module et un fichier modèle. Tous les modules sont contenus dans le dossier modules. J'ai pris l'habitude de placer les fichiers modèles dans un dossier externe distinct, le dossier tpl.
config.php - le fichier de configuration central, contenant toutes les variables de configuration globales.
index.php - Contrôleur, sera décrit en détail dans le prochain article.
object.php - la classe sous-jacente à toutes les classes de base, fournissant la plupart des fonctionnalités nécessaires à la classe. FR_Object_DB hérite de cette classe et fournit des liens de base de données.
Le concept de base d’une structure est que toutes les sous-classes héritent d’une classe centrale afin qu’elles partagent toutes certaines caractéristiques communes. Vous pouvez mettre la fonction de liaison vers la base de données dans FR_Object, mais toutes les classes n'ont pas besoin de cette fonction, donc FR_Object_DB a une raison d'être, et l'auteur en discutera plus tard.
<?php
require_once('Log.php');
/**
*FR_Objet
*
* La classe d'objets de base pour la plupart des classes que nous utilisons dans notre framework.
* Fournit une journalisation de base et des fonctionnalités de définition/obtention.
*
* @auteur Joe Stump < [email protected] >
* @packageFramework
*/
classe abstraite FR_Object
{
/**
* $log
*
* @var mixte $log Instance du journal PEAR
*/
$log protégé ;
/**
*$moi
*
* @var a mélangé une instance $me de ReflectionClass
*/
protégé $moi ;
/**
* __construire
*
* @auteur Joe Stump < [email protected] >
* @accès public
*/
fonction publique __construct()
{
$this->log = Log::factory('file',FR_LOG_FILE);
$this->me = new ReflectionClass($this);
}
/**
* setFrom
*
* @auteur Joe Stump < [email protected] >
* @accès public
* @param mixte $data Tableau de variables à attribuer à l'instance
* @retour nul
*/
fonction publique setFrom($data)
{
if (is_array($data) && count($data)) {
$valid = get_class_vars(get_class($this));
foreach ($valable comme $var => $val) {
if (isset($data[$var])) {
$this->$var = $data[$var];
}
}
}
}
/**
* versArray
*
* @auteur Joe Stump < [email protected] >
* @accès public
* @return Tableau mixte de variables membres saisies par nom de variable
*/
fonction publique toArray()
{
$defaults = $this->me->getDefaultProperties();
$retour = tableau();
foreach ($par défaut comme $var => $val) {
if ($this->$var instanceof FR_Object) {
$return[$var] = $this->$var->toArray();
} autre {
$return[$var] = $this->$var;
}
}
retourner $retour ;
}
/**
* __destruct
*
* @auteur Joe Stump < [email protected] >
* @accès public
* @retour nul
*/
fonction publique __destruct()
{
if ($this->log instanceof Log) {
$this->log->close();
}
}
}
?>
auth.php – Il s'agit de la classe sous-jacente à toutes les fonctionnalités d'authentification. Il est une extension de FR_Module et sa fonction principale est de définir le fonctionnement d'une classe de vérification de base.
Tout comme FR_Module, certaines classes n'ont pas besoin d'être connectées à la base de données. De la même manière, FR_Auth_No peut être créé et appliqué à des classes qui ne nécessitent pas de fonctions d'authentification.
<?php
la classe abstraite FR_Auth étend FR_Module
{
// {{{ __construct()
fonction__construct()
{
parent::__construct();
}
// }}}
// {{{ authentifier()
fonction abstraite authentifier();
// }}}
// {{{ __destruct()
fonction __destruct()
{
parent::__destruct();
}
// }}}
}
?>
module.php - le cœur de tous les modules
<?php
la classe abstraite FR_Module étend FR_Object_Web
{
// {{{ propriétés
/**
* $présentateur
*
* Utilisé dans FR_Presenter::factory() pour déterminer quelle présentation (vue)
* La classe doit être utilisée pour le module.
*
* @auteur Joe Stump < [email protected] >
* @var chaîne $présentateur
* @voir FR_Presenter, FR_Presenter_common, FR_Presenter_smarty
*/
public $presenter = 'intelligent';
/**
* $données
*
* Données définies par le module qui seront éventuellement transmises à la vue.
*
* @auteur Joe Stump < [email protected] >
* @var mixte $data Données du module
* @voir FR_Module::set(), FR_Module::getData()
*/
protégé $data = tableau();
/**
* $nom
*
* @auteur Joe Stump < [email protected] >
* @var string $name Nom de la classe du module
*/
public $nom
/**
* $tplFichier
*
* @auteur Joe Stump < [email protected] >
* @var string $tplFile Nom du fichier modèle
* @see FR_Presenter_smarty
*/
public $tplFichier
/**
* $nomdumodule
*
* @auteur Joe Stump < [email protected] >
* @var string $moduleName Nom du module demandé
* @see FR_Presenter_smarty
*/
public $moduleName = null ;
/**
* $pageTemplateFichier
*
* @auteur Joe Stump < [email protected] >
* @var string $pageTemplateFile Nom du modèle de page externe
*/
public $pageTemplateFile = null ;
// }}}
// {{{ __construct()
/**
* __construire
*
* @auteur Joe Stump < [email protected] >
*/
fonction publique __construct()
{
parent::__construct();
$this->name = $this->me->getName();
$this->tplFile = $this->name.'.tpl';
}
// }}}
// {{{ __défaut()
/**
* __défaut
*
* Cette fonction est exécutée par le contrôleur si un événement n'est pas spécifié
* dans la demande de l'utilisateur.
*
* @auteur Joe Stump < [email protected] >
*/
fonction publique abstraite __default();
// }}}
// {{{ set($var,$val)
/**
* ensemble
*
* Définissez les données de votre module. Celles-ci seront éventuellement transmises au module.
* classe présentateur via FR_Module::getData().
*
* @auteur Joe Stump < [email protected] >
* @param string $var Nom de la variable
* @param mixte $val Valeur de la variable
* @retour nul
* @see FR_Module::getData()
*/
ensemble de fonctions protégées ($var,$val) {
$this->data[$var] = $val;
}
// }}}
// {{{ getData()
/**
*getData
*
* Renvoie les données du module.
*
* @auteur Joe Stump < [email protected] >
* @retour mixte
* @voir FR_Presenter_common
*/
fonction publique getData()
{
renvoie $this->data ;
}
// }}}
// {{{ estValide($module)
/**
*estValide
*
* Détermine si $module est un module de framework valide. Ceci est utilisé par.
* le contrôleur pour déterminer si le module s'intègre dans notre framework
* mold S'il s'étend à la fois de FR_Module et FR_Auth, alors il devrait l'être.
* bon à courir.
*
* @auteur Joe Stump < [email protected] >
* @statique
* @param mixte $module
* @return booléen
*/
fonction statique publique isValid($module)
{
retourner (is_object($module) &&
$module instance de FR_Module &&
$module instance de FR_Auth);
}
// }}}
// {{{ __destruct()
fonction publique __destruct()
{
parent::__destruct();
}
// }}}
}
?>
presenter.php - le cœur de la couche de présentation.
<?php
classe FR_Presenter
{
// {{{ usine($type,FR_Module $module)
/**
*usine
*
* @auteur Joe Stump < [email protected] >
* @accès public
* @param string $type Type de présentation (notre point de vue)
* @param Mixed $module Notre module, que le présentateur affichera
* @return mixte PEAR_Error en cas d'échec ou d'un présentateur valide
* @statique
*/
usine de fonctions publiques statiques ($type,FR_Module $module)
{
$file = FR_BASE_PATH.'/includes/Presenter/'.$type.'.php';
si (inclure ($ fichier)) {
$class = 'FR_Presenter_'.$type;
si (class_exists($class)) {
$présentateur = nouveau $class($module);
if ($presenter instanceof FR_Presenter_common) {
retourner $présentateur ;
}
return PEAR::raiseError('Classe de présentation invalide : '.$type);
}
return PEAR::raiseError('Classe de présentation introuvable : '.$type);
}
return PEAR::raiseError('Fichier présentateur introuvable : '.$type);
}
// }}}
}
?>
Dans le prochain article, je présenterai la structure du contrôleur (Contrôleur en MVC, index.php dans cet article). Dans le troisième article, je présenterai la couche de présentation (View in MVC). Dans le quatrième article, j'utiliserai un module spécifique comme exemple pour créer une application (Module ou Modèle en MVC).