Consultez la FAQ sur le ZF avant de poster une question
Vous n'êtes pas identifié.
Bonjour à tous !
Me revoilà avec une nouvelle question ^^
Je voudrais créer des fonctions appelables nativement (j'entend par là : sans les appeler sur un objet ou une classe).
Des exemples :
__($string) qui traduit $string en fonction du code pays
__HTTP(mixed params) qui utilise les params pour générer des url (celà dépend de beaucoup de choses, comme l'OS du serveur, https ou non, le nom de domaine, etc... tout cela stocké dans des fichiers de config)
__DB(mixed params) qui retournes la bonne config pour créer un adapter (pareil, on a beaucoup de serveurs de DB, tres hétéroclytes)
Ces fonctions, pour être maniables, devraient pouvoir être appelées telles quelles, sans avoir besoin d'écrire UneClasse::__HTTP() par exemple. Ca serait trop lourd
Ma solution pour l'instant, c'est d'inclure un bon vieux fichier de fonctions en procédural dans le bootstrap. Effet garanti. Mais ouch, quelle horreur !
Alors ma question : existe-t-il un endroit approprié où placer ces fonctions, que je suis susceptible d'appeler dans les controllers aussi bien que dans les vues ?
Dernière modification par Bast (27-06-2008 10:44:05)
Hors ligne
Le moyen propre pour ce genre de truc, c'est le "singleton". Je te laisse regarder dans google, tu devrais avoir quelques millions de réponses... (en gros c'est une classe qui ne peut avoir qu'une seule instance et que tu peux utiliser partout dans ton code)
A+, Philippe
Hors ligne
Dans mon bootstrap j'ai toutes mes includes et cette ligne
Scholastie::run();
Scholastie (il est trop moche ce prénom, et c'est le deuxième de ma copine ) est une classe contenant que des fonctions et variables statiques, donc globales. Dedans, je découpe le contenu d'un bootstrap et je retrouve la fonction setupEnvironnement() et prepare() qui contient toutes les fonctions de types :
self::setupFrontController(); self::setupConfiguration(); self::setupRoute(); self::setDefaultController(); self::setupCache(); self::setupRegistry(); self::setupListBD(); self::setupIni_DbSectionName(); //-- charge les paramètres de la base de données à utiliser self::setupDatabase(); //-- charge la base de données en prenant compte des informations ci-dessus self::setupView(); self::setupAcl(); self::setupMenu(); self::initProfiling(false); //-- Profiling de la db
Si j'aurai voulu ajouter une fonction ou variable globale, je l'aurai mis en static ici.
Dernière modification par whitespirit (27-06-2008 07:12:39)
Hors ligne
Merci Philippe, mais en passant par un singleton, je devrai appeler mes fonctions de cette manière :
$mon_singleton->__fonction() ;
Or, je voudrais y accéder de partout en ne faisant que :
__fonction() ;
White : c'est pas bien de chambrer ta copine !!
Tu lances le run() de Scholastie dans ton bootstrap ? Ce fameux run() appelle toutes tes fonctions self::bla() ?
Je ne vois pas bien comment implémenter mes fonctions statiques dans scholastie, ni comment les rendre accessibles à toutes les autres classes... Tu aurais un exemple ?
Merci ^^
Hors ligne
Bonjour Bast,
En fait c'est pire que ce que tu dis, dans un code tu appelles ta fonction par :
MonSingleton::getInstance()->__fonction();
cela dit ça a 2 intérêts :
- ça sépare bien le code. Si tu veux regrouper 2 sites en un, tu n'as pas à dédoublonner tes fonctions globales
- si certains fonctions "globales" on besoin d'être initialisées, tu peux les initialiser dans ton bootstrap en injectant les données dans ton objet (tu peux chercher "injection de dépendance" dans google, tu auras encore quelques millions de réponses).
Bon... sur un petit projet ta méthode marche aussi bien... te prends pas forcément la tête là dessus, mais garde dans un coin de ta tête le fait que ça existe pour un plus gros projet
A+, Philippe
Hors ligne
Qu'appelles tu par "initialiser" une fonction ?
Ce ne sont pas de petits projets. Et il y en a un paquet (une 10 aine de sites, au bas mot)
-> je vais faire des recherches sur l'injection de dépendances (mais déjà l'expression me déplait, je hais les dépendances xD )
Edit : ok je vois ce que c'est. Sauf que je ne sais pas vraiment en quoi l'injection de dépendances m'aiderait dans ce cas là !
Ma seule demande, c'est : Comment faire pour appeler mes fonctions directement, sans $un_objet->, ou pire, UneClasse::getInstance()-> devant ?
Dernière modification par Bast (27-06-2008 10:31:22)
Hors ligne
Justement l'injection de dépendance permet d'avoir le projet global qui ne dépend pas des "classes outils" qu'il utilise...
Le problème posé :
Imagine une classe qui se charge d'écrire des logs. Tu peux décider de dire le répertoire de logs c'est LOG_DIR et je code ma classe en mettant la constante LOG_DIR en dur dedans.
Le problème est que le fonctionnement de ta classe impose au site la présence de la constante LOG_DIR, tu as donc une dépendance de ton site à ton système de logs.
La solution : l'injection de dépendance (ou inversion de contrôle, tu trouveras les 2 dans la littérature)
dans ta classe de logs, tu crées une méthode setLogDir($dir).
Dans ce cas ta classe de log n'impose rien au reste du site, c'est le site qui dit à la classe de log que le répertoire est celui ci ou celui là.
un autre exemple : le routeur du ZF :
Dans son code, le ZF utilise de façon systématique l'injection de dépendance. Par exemple ton routeur n'impose rien à ton appli, c'est ton bootstrap qui injecte les données dans le routeur. Tes données de routage, peuvent être dans un config.ini, des constantes ou n'importe quoi, le routeur s'en fout... c'est en ça que ton appli est beaucoup plus indépendante de ton routeur...
Sinon ce que j'appelle un gros projet, c'est un projet avec plusieurs développeurs avec chaque développeur qui doit faire évoluer le code des autres de temps à autre... là si le code n'est pas très standard et formalisé, on met 2 fois plus de temps à le reprendre. Accessoirement ça peut donner des envies de meurtre assez récurrentes
A+, Philippe
Dernière modification par philippe (27-06-2008 10:36:03)
Hors ligne
Pour ton problème en particulier... un include dans ton bootstrap avec les fonctions globales dedans... ça marche bien
A+, Philippe
Hors ligne
Ce que tu viens d'expliquer, nous l'appliquons déjà dans nos scripts. On fait tout pour virer un maximum de dépendances (notamment, comme tu l'as fait remarquer, les constantes qui ne doivent surtout pas être ne dur dans le code, mais externalisées).
J'ai parfaitement compris tes explications.
Edit : Après lecture de ton deuxième post, la phrase suivante n'a plus lieu d'être :
Cependant, je n'ai toujours pas compris où écrire le code de mes fonctions, ni comment, au final, les appeler nativement...
Merci à tous pour votre aide !
Dernière modification par Bast (27-06-2008 10:43:44)
Hors ligne
Entre temps vous avez bien discuter à ce sujet, donc je ne sais pas si ma solution est toujours d'actualité. Dans le doute je te donne plus de détail :
- en dehors des includes dans mon index.php j'ai donc uniquement Scholastie::run() (serieux, scholastie !!!! mais heureusement que c'est son deuxième prénom, et que le premier ne soit pas Robert) dont voici le code (je n'ai volontairement pas épuré le code pour que tu vois concrètement ce qu'il y'a exactement à l'intérieure des principales fonctions)
/** * Lance l'application après avoir initialisé les variables * */ public static function run() { self::setupEnvironment(); self::prepare(); try { $response = self::$frontController->dispatch(); self::sendResponse($response); //=========================================== // Si le profiling de db est activé //=========================================== if (self::$is_profiling_on == true) { $db = self::$registry->database; $start = microtime(true); $longestTime = 0; $longestQuery = null; $end = microtime(true) - $start; // ici du capture le temps d'execution total du script (code+bdd) $profiler = $db->getProfiler(); foreach ($profiler->getQueryProfiles() as $query) { if ($query->getElapsedSecs() > $longestTime) { $longestTime = $query->getElapsedSecs(); $longestQuery = $query->getQuery(); } } $totalTime = $profiler->getTotalElapsedSecs(); $queryCount = $profiler->getTotalNumQueries(); echo "totalTime :$totalTime <br /> queryCount : $queryCount <br> Requête plus longue : $longestQuery"; } } catch (Exception $exception) { exit( $exception->getMessage().'<br/>'. $exception->getfile().' à la ligne '. $exception->getLine().'<br/>' ); } } /** * Setup de l'environnement * */ public static function setupEnvironment() { error_reporting(E_ALL|E_STRICT); date_default_timezone_set('Europe/Paris'); ini_set('session.save_path', './data/sessions'); Zend_Session::start(); self::$scholastieNamespace = new Zend_Session_Namespace(self::$TXT_NAME_SESSION); self::$root = dirname(dirname('<u>_FILE_</u>')); } /** * Appel tous les autres setup et charge les paramètres d'applications * */ public static function prepare() { //**************************************************************** // PARAMETRE DE CONFIGURATION A PLACER DANS LE FICHIER INI //**************************************************************** $type_checkbox_liste = TK_CB_CHECK; Zend_Registry::set('type_checkbox_liste', $type_checkbox_liste); Zend_Loader::registerAutoload(); self::setupFrontController(); self::setupConfiguration(); self::setupRoute(); self::setDefaultController(); self::setupCache(); self::setupRegistry(); self::setupListBD(); self::setupIni_DbSectionName(); //-- charge les paramètres de la base de données à utiliser self::setupDatabase(); //-- charge la base de données en prenant compte des informations ci-dessus self::setupView(); self::setupAcl(); self::setupMenu(); self::initProfiling(false); //-- Profiling de la db }
Je ne sais pas ce qu'en pense les puristes, moi je n'en suis pas un. Mais cette solution réponds à mes besoins (pour l'instant). Le seul truc important c'est que tous les paramétres sont chargés dans un fichier .ini, et que j'ai une conception modulaire (au sens propre et non ZF) ce qui veut dire que rien n'est dépendant. Ceci dit, quand j'ai commencé à codé je ne connaissais pas design pattern Singleton
Hors ligne