8791 sujets

Développement web côté serveur, CMS

Bonjour,

En travaillant sur un projet en PHP j'ai constaté les faits suivant:

-Il est possible de déclarer une fonction dans une fonction.
-Il est possible de déclarer une classe dans une fonction.
-Il est possible de déclarer une fonction dans une méthode.
-Il n'est pas possible de déclarer une classe dans une méthode.

Par contre, si l'on inclus un fichier via un include(), require() ou require_once(). Il devient également possible de déclarer une classe dans une méthode.


class nouvelleClasse
{
	public function __construct()
	{
		class classeImbrique
		{
			public function __construct()
			{
			}
		}
	}
}

Ne fonctionnera pas. Mais:

class classeImbrique
{
	public function __construct()
	{
	}
}



class nouvelleClasse
{
	public function __construct()
	{
	require_once('classeImbrique.php')
	}
}

Cette fois cela fonctionne.

Je me demandais si le fait de déclarer des fonctions ou des classes à l'intérieur d'autres fonctions ou méthodes était à proscrire pour une raison quelconque? Bien évidemment il faut s'assurer que la fonction ou la méthode "parente" à bien été appelé avant de tenter d'appeler une fonction ou une méthode "fille" et il faut faire attention à la portée des variables contenues dans les fichiers inclus, mais à part ces quelques points à vérifier y a-t-il d'autres contres indications à utiliser une tel façon de faire?

Je me pose la question, puisqu'il me semble pratique de ne charger que les classes nécessaires selon ce que doit faire ou afficher le script. Par exemple, dans un CMS, un contrôleur principal pourrait via une méthode inclure les classes nécessaire pour tel type de page à afficher au lieu d'inclure tous les fichiers des classes de chaque type de page dans le script.

De plus, puisque include() et require() sont supposé être l'équivalent de créer un gros script unique, pourquoi les deux exemples placés plus haut ne donne pas le même résultat en causant une erreur de classe imbriqué?

Merci d'avance pour vos précisions!
Modifié par gizz (11 Jun 2010 - 19:23)
Lorsqu'on inclut un script dans un autre grâce à include ou require, les classes et les fonctions définies dans le fichier inclus sont globales. Seul ce qui ne fait pas partie d'une fonction ou d'une classe atterrit effectivement dans la portée courante.

Pour le reste, je n'ai jamais essayé les classes internes en php, donc je ne saurais te répondre avec exactitude. Par contre, précise si tu es en php 5.2 ou 5.3, parce que je crois qu'il y a eu pas mal de changements dans ce genre de constructions.
QuentinC a écrit :
Lorsqu'on inclut un script dans un autre grâce à include ou require, les classes et les fonctions définies dans le fichier inclus sont globales. Seul ce qui ne fait pas partie d'une fonction ou d'une classe atterrit effectivement dans la portée courante.

Ce qui fait qu'inclure 2 fois la même classe/fonction équivaut à une erreur "Fatal error: Cannot redeclare …"

QuentinC a écrit :
Je me pose la question, puisqu'il me semble pratique de ne charger que les classes nécessaires selon ce que doit faire ou afficher le script. Par exemple, dans un CMS, un contrôleur principal pourrait via une méthode inclure les classes nécessaire pour tel type de page à afficher au lieu d'inclure tous les fichiers des classes de chaque type de page dans le script.

Et il y a le problème au-dessus. Donc il faudrait mettre une condition pour ne pas remettre la classe/fonction si elle existe déjà. Et inclure un fichier n'est pas très long.
Le mieux est d'utiliser l'auto-chargement de classes.

Personnellement je n'inclut rien dans met fonction alors je ne sais pas si c'est vraiment utile.
Premièrement pour le problème de la double définition de classe ou de fonction, il est certains qu'il faut toujours utiliser include_once() ou require_once() pour ce genre d'utilisation.

Le problème de l'auto-chargement de classes, c'est qu'on doit:
-Mettre chaque classe dans un fichier unique du nom de la classe et tous les mettre dans un dossier unique.
OU
-Mettre chaque classe dans un fichier unique du nom de la classe et créer un fonction de recherche qui parcourt différents dossier pour trouver la classe.

Ce qui devient plutôt compliqué lorsqu'il s'agit de programme volumineux divisé en modules indépendant ayant chacun son dossier propre.

De plus, cela se limite au classes. Il n'est pas possible de faire la même choses pour des fonctions ou des variables, constantes, etc.. Si par exemple, j'ai une méthode qui récupère dans une base de données le type de la page à afficher et qu'ensuite, il inclus dans le script les fichiers contenant les classes, les fonctions, les constantes et les variables nécessaires pour ce type de page....comment puis-je faire sans utiliser d'inclusions?

Il me semble qu'inclure l'ensemble des fichiers contenant les fonctions, variables et constantes de tout le programme (en utilisant l'auto-chargement pour les classes au moins) rendrait le programme beaucoup plus lourd et lent que seulement inclure les fichiers spécifiques. Non? Que serait les autres solutions?

P.S. Je suis actuellement en PHP 5.2.13
Modifié par gizz (11 Jun 2010 - 20:48)
gizz a écrit :
Premièrement pour le problème de la double définition de classe ou de fonction, il est certains qu'il faut toujours utiliser include_once() ou require_once() pour ce genre d'utilisation.

Oui c'est vrai, j'étais resté dans l'idée si en plus il y a du code qui doit s'exécute Smiley lol .

gizz a écrit :
Le problème de l'auto-chargement de classes, c'est qu'on doit:
-Mettre chaque classe dans un fichier unique du nom de la classe et tous les mettre dans un dossier unique.
OU
-Mettre chaque classe dans un fichier unique du nom de la classe et créer un fonction de recherche qui parcourt différents dossier pour trouver la classe.

Tu peux aussi "trouvé" le fichier grâce au nom de de la classe. Exemple Ma_Super_Classe est le fichier Ma/Super/Classe.php. En fonction de majuscule, ou un autre algo. Puis c'est possible de mettre plusieurs classe dans le même fichier, faudra juste peut-être faire attention à la classe appeler pour inclure le fichier ou faire des liens symboliques (ça évite les prises de tête).

gizz a écrit :
Ce qui devient plutôt compliqué lorsqu'il s'agit de programme volumineux divisé en modules indépendant ayant chacun son dossier propre.

Si le nom de classe est bien choisi on peut faire comme dit juste au-dessus.

gizz a écrit :
De plus, cela se limite au classes. Il n'est pas possible de faire la même choses pour des fonctions ou des variables, constantes, etc..

C'est vrai. Il faut inclure le(s) fichier(s) requis.
C'est aussi possible de faire des classes statique et mettre des fonction, constanrts, etc avec... Mais c'est peut-être pas la meilleure solution.

gizz a écrit :
Si par exemple, j'ai une méthode qui récupère dans une base de données le type de la page à afficher et qu'ensuite, il inclus dans le script les fichiers contenant les classes, les fonctions, les constantes et les variables nécessaires pour ce type de page....comment puis-je faire sans utiliser d'inclusions?.

Bah c'est pas possible, non ? Faudra au moins l'include pour la page à afficher. Le but n'est pas d'inclure le moins possible quand même ^^' ?

gizz a écrit :
Il me semble qu'inclure l'ensemble des fichiers contenant les fonctions, variables et constantes de tout le programme (en utilisant l'auto-chargement pour les classes au moins) rendrait le programme beaucoup plus lourd et lent que seulement inclure les fichiers spécifiques. Non? Que serait les autres solutions?

Le principe de l'auto-chargement est d'inclure au besoin. Si ce n'est pas utilisais, ce n'est pas inclut Smiley cligne .
L'autre solution comme tu le devines est de mettre tout les includes au début du fichier (ou dans les fonctions). Mais que c'est moins pratique et source d'oubli.
En fait je crois qu'on est plutôt d'accord sur la plupart des points, mais qu'on s'est exprimé de façon différente.

Si je fais une synthèse de tout ça... l'idéal c'est d'avoir un script principal avec une fonction __autoload() pour charger les classes nécessaire au fonctionnement du script. Cette fonction peut avoir un système de localisation de classe basé sur le fait que les classes comporteraient dans leur nom le nom du module et autre éléments hiérarchique de façon a ce que par exemple monModule_maClasse() se retrouve dans le dossier modules/monModule/maClasse/ .

Là où je me questionne, c'est si j'ai un pack de fonction hors classes (ce qui peut être pratique... PHP n'est pas un langage vraiment objet de toute façon) et que disons certaines constantes et/ou variables (placé globalement) sont nécessaire au fonctionnement de certains modules. Il faut ajouter un require_once() pour ajouter tout ça. Mais je ne peut savoir quels packs seront nécessaire en partant. C'est un objet contrôleur qui après avoir reçu le type de page à afficher qui devra ajouter les fichiers du module relié. Les classes sont gérés automatiquement grâce à l'autoload ce n'est plus un problème. Par contre pour les fonctions et les variables je n'ai pas le choix de mettre un require_once à l'intérieur d'une fonction ou d'une méthode si je veut pouvoir dynamiquement choisir ce que je charge. Ma question initiale était si cela était à éviter à tout prix ou non et dans l'affirmative l'alternative qui existerait.

La seule solution qui me vient à l'esprit serait que les fonctions, constantes et variables soit inclus dans le fichier de la classe mère du module. De cette façon lorsque on crée un instance de la classe mère, le script charge le fichier de la classe et du même coup toutes les autres fonctions reliés. Par contre cela oblige d'avoir un script très orienté objet qui crée un instance mère pour chaque module appelé. De plus, je ne vois pas grand différences entre cela et un require()...

Ok ok... je sais... pourquoi me compliqué la vie comme ça et ne pas plutôt choisir de programmer 100% procédural ou 100% objet.... mais l'objet j'adore... mais j'ai encore un peu de difficultés à penser 100% objet... parfois je trouve que ça complique les choses... pourquoi créer une classe et devoir faire une instance pour pouvoir faire une simpe fonction... ok y a les statics.. mais encore là... pourquoi écrire maClasse::maFonction() plutot que seulement maFonction() si la fonction n'est qu'un in->out sans interactions autres avec le programme... Smiley langue

EDIT: En passant, j'utilise déjà le fait d'inclure des fichiers via une fonction ou une méthode dans un de mes anciens scripts (À l'époque j'avais même pas réalisé la chose). Ça fonctionne très bien dans mon cas, mais je me demandais plus si cela pouvait causer problème et donc ne devrais pas être utilisé ou si d'autres options étaient présentes!
Modifié par gizz (12 Jun 2010 - 01:40)
gizz a écrit :
Par contre pour les fonctions et les variables je n'ai pas le choix de mettre un require_once à l'intérieur d'une fonction ou d'une méthode si je veut pouvoir dynamiquement choisir ce que je charge. Ma question initiale était si cela était à éviter à tout prix ou non et dans l'affirmative l'alternative qui existerait.

Non, Ça marche très bien.
Y a aussi le fichier intermédiaire avec à l'intérieur touts les includes, mais c'est pareil au final.
IL n'est pas interdit d'avoir des fonctions isolées non plus.

Dans mon mini-CMS à moi par exemple, les fonctions spécifiques à l'affichage (les récurrentes fonctions de formatage de nombre, date, anti XSS et autres, bref les candidates indépendantes par excellence), sont chargées par un require_once au début de la définition de la classe Template. Cette classe peut être chargée par autoload et on ne se trimballe pas une classe bidon qui ne contient que des méthodes statiques.

Ca part évidemment du principe que si on a besoin du générateur de template, alors on aura probablement également aussi besoin de ces fonctions, et inversément. ET si d'aventure on avait besoin des fonctions d'affichage sans le générateur (cas supposé improbable), eh bien, un require_once n'a jamais tué personne.

Le php permet d'utiliser aussi bien l'objet que le procédural. Prenons le meilleur de chaque monde , et profitons-en. Des classes qui ne contiennent que des méthodes statiques, en php, franchement, ça n'a aucun intérêt.
QuentinC a écrit :
Le php permet d'utiliser aussi bien l'objet que le procédural. Prenons le meilleur de chaque monde , et profitons-en. Des classes qui ne contiennent que des méthodes statiques, en php, franchement, ça n'a aucun intérêt.


Oui et non... un premier intérêt est justement de pouvoir charger uniquement ce que tu as besoin, par exemple Date::toArray c'est pas beaucoup plus long que dateToArray, et cela te permet à la fois de ne pas charger les fonctions de date si tu n'en a pas besoin, et de ne pas te préoccuper de l'inclure si tu en as besoin. Cela évite également les collisions de noms si jamais la fonction existe déjà. Tu peux ainsi séparer des fonctions utiles "statiques" dans des fichiers indépendant, Date, Text, Security etc...
Modifié par matmat (13 Jun 2010 - 23:39)
Bah j'ai une classe avec seulement des méthodes statiques, mais qui utilise des objets de la classe en interne. En plaçant le constructeur en private et en insérant la création d'un objet de la classe dans une méthode comme createInstance(). Les instances sont placé dans un tableau static de la classe et la méthode retourne la clé du tableau correspondant à l'instance. Pour jouer dans les instances il faut passer par des méthodes statiques dont certaines en plaçant en paramètre la clé de l'instance. C'est pas toujours utile, mais dans certains cas où l'on veut centraliser toutes les instances d'un objet et s'assurer que rien dans le script ne modifie les instances autres que les méthodes de la classe...