"include" dans une classe qui "include" d'autres classes...

Petit nouveau ! | 2 Messages

19 févr. 2010, 14:44

Bonjour à tous.
Je n'ai pas de pbm particulier mais une lacune de langage je pense. J'ai un projet qui ressemble à l'architecture suivante :

Code : Tout sélectionner

|->classes | | |classes de projet | |-> classe d'api |-> inc
Dans le dossier classes, j'ai mes classes de projets et un dossier de classes (api) qui passent des requêtes à diverses API (Bing, Boss, Flickr, etc...) et qui include un petit curl.inc.php (non POO, contient juste une fonction avec des params pour personnaliser CURL) qui se trouve dans le dossier inc afin de lire les contenus. J'utilise indifféremment les classes d'api sans pbm (en REMOTING AMFPHP+FLASH), mais je souhaiterai mettre en place un mashup dans le dossier des classes. Le problème est que lorsque j'include les fichiers de classes d'api pour créer des objets dans mon mashup, le lien avec le curl.inc.php (inclus dans les classes d'api) est rompu. Fatal error: main(): Failed opening required '../../inc/curl.inc.php etc... En fait, je ne savais pas que lorsqu'on "includait" un fichier qui lui-même "includait" d'autres fichiers, le chemin de ces derniers devenait relatif au premier "includer"... :shock:
Existe-t'il un moyen de modifier cela ? Je sais que c'est bêta mais j'aime BEAUCOUP l'architecture de mes dossiers, c'est clair pour moi...

Merci. :)

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

19 févr. 2010, 15:36

Si tu développes en PHP 5.3, il existe une instruction __DIR__ qui contient le chemin complet du dossier qui contient le fichier dans lequel se trouve l'instruction.
Ainsi, tu es sur que, quelques soit le fichier depuis lequel est inclu ton fichier d'inclusion, cette instruction te retournera toujours la même chose.

Il faut donc écrire tes inclusions comme suit :
require_once( __DIR__ .'../../inc/curl.inc.php');
Si tu utilises PHP 5.2, l'instruction __DIR__ n'existe pas, mais il existe l'instruction __FILE__ qui te retourne le chemin complet jusqu'au fichier courant.
Donc, pour obtenir le même résultat que __DIR__ quand tu utilises PHP 5.2, il faut écrire
dirname(__FILE__); // retourne le chemin complet du dossier contenant le fichier courant
et du coup, tes inclusions seront de la forme suivante :
require_once( dirname(__FILE__) .'../../inc/curl.inc.php');
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Petit nouveau ! | 8 Messages

28 févr. 2010, 10:21

salut,

attention au fait que la fonction dirname ne retourne pas de slash en fin de chaîne. Il faut donc écrire :

Code : Tout sélectionner

require_once( dirname(__FILE__) .'/../../inc/curl.inc.php');
et non pas

Code : Tout sélectionner

require_once( dirname(__FILE__) .'../../inc/curl.inc.php');
Note : dirname( __FILE__ ) peut poser problème si vous avez des liens symboliques dans votre système de fichiers. Une autre alternative serait d'utiliser

Code : Tout sélectionner

$_SERVER[ "DOCUMENT_ROOT" ]
++

Mammouth du PHP | 985 Messages

05 mars 2010, 17:07

Sinon il y a une petite variante, en utilisant realpath():
if (!defined('__DIR__')) { 
    define('__DIR__', realpath(dirname(__FILE__)));
}
[EDIT]
Correction: désolé :mrgreen:
Face à la roche, le ruisseau l'emporte toujours, non pas par la force mais par la persévérance.

devlop78
Invité n'ayant pas de compte PHPfrance

24 mars 2010, 15:14

En fait, je ne savais pas que lorsqu'on "includait" un fichier qui lui-même "includait" d'autres fichiers, le chemin de ces derniers devenait relatif au premier "includer"...

Moi non plus ... et je trouve ça bizarre ... je ferai un test mais ça m'étonne. Sinon tu as la méthode absolue /var/www/virtual/toi/htdocs/ mais je ne me souviens pas avoir eu des pb comme ça. Normalement tes includes se font par rapport au dossier en cours, c'est à dire (par défaut) au dossier du fichier php appelé en tout premier. Mais il est possible que je me trompe vu ton problème.

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

24 mars 2010, 16:13

justement, c'est là tout le soucis.

On reprend.
Voici l'arborescence de base :

Code : Tout sélectionner

base/ libs/ classe1.class.php classe2.class.php actions/ action.class.php controler.php
imaginons que tu commences à développer ta classe2, et que tu rendes compte que tu ais besoin de la classe1.
Tu vas donc commencer le fichier "classe1.class.php" comme suit :
<?php
// base/lib/classe1.class.php
require_once('classe2.class.php');

// ...
Du coup, si tu exécutes le fichier "classe1.class.php", tout va fonctionner.

Maintenant, tu as terminé ta classe1, tu veux l'utiliser.
Tu ouvres donc le fichier "action.class.php", et tu inclus la classe1 (à ce moment, tu ne te rappelles même plus que tu as besoin de classe2 pour utiliser classe1), comme suit :
<?php
// base/action/action.class.php
require_once('../lib/classe1.class.php');

// ...
Et là, c'est le drame, il te dit qu'il ne peut trouver le fichier classe2, et il te montre qu'il la cherché au chemin "base/action/classe2.class.php". Tout ça parce que le require, si le chemin n'est pas absolue, recherche relativement au dossier contenant le fichier de base (soit, dans notre cas, "base/action"). Et, du coup, le require_once('classe2.class.php') ne fonctionne pas.
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Mammouth du PHP | 568 Messages

24 mars 2010, 16:16

Et l'autoload ne serait-il pas la solution la plus simple ici?

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

24 mars 2010, 16:17

Il existe bien entendu plusieurs solutions, qui vont de l'autoload (mieux) au pauvre fichier d'inclusion générique (et un chaton mort, un)

La solution que j'ai donné permet d'utiliser les require_once() en s'affranchissant du fichier de base.
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

devlop78
Invité n'ayant pas de compte PHPfrance

25 mars 2010, 02:06

Zeus, entièrement d'accord avec toi. Mais on est d'accord qu'il fait l'include par rapport au dossier courant du fichier initialement appelé, et non par rapport au dossier courant du fichier inclus (un peu compliqué :oops: ).

Une solution serait d'avoir un fichier load.php (je dis ça comme ça) avec une classe dedans qui se charge de faire les includes (et qui fait tout par rapport à lui __FILE__ et autres). Ou d'avoir un magnifique define('INIT_DIR_", "/var/www/virtual/moi.com/htdocs/"); au début d'un fichier que tous les scripts appelerait ... un peu comme Wordpress fait je crois ...

ViPHP
ViPHP | 5462 Messages

25 mars 2010, 04:33

le top c'est de mettre ca lib dans le set_include_path et la pas de soucis de path

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

25 mars 2010, 11:22

Zeus, entièrement d'accord avec toi. Mais on est d'accord qu'il fait l'include par rapport au dossier courant du fichier initialement appelé, et non par rapport au dossier courant du fichier inclus (un peu compliqué :oops: ).
Oui, c'est ce que j'essayais de dire ;)
Mais, comme tu le dis, c'est pas simple à expliquer.
Une solution serait d'avoir un fichier load.php (je dis ça comme ça) avec une classe dedans qui se charge de faire les includes (et qui fait tout par rapport à lui __FILE__ et autres). Ou d'avoir un magnifique define('INIT_DIR_", "/var/www/virtual/moi.com/htdocs/"); au début d'un fichier que tous les scripts appelerait ... un peu comme Wordpress fait je crois ...
Cette solution est limitée dans le sens que tout est tout le temps inclu, et c'est pas top.
le top c'est de mettre ca lib dans le set_include_path et la pas de soucis de path
C'est un peu mieux, mais ça me donne des frissons.

LA solution qui me semble la plus adaptée, c'est l'autoloading
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

devlop78
Invité n'ayant pas de compte PHPfrance

25 mars 2010, 17:19

Cette solution est limitée dans le sens que tout est tout le temps inclu, et c'est pas top
.

Je me suis mal exprimée ... cette fonction ou cette classe se charge d'inclure la classe que tu lui demande. En gros, c'est un autoload. par exemple si tu fais f_classe("MaClasse") ça inclura le fichier MaClasse.class.php ... mais en gros c'est de l'autoload lol.
set_include_path
Perso, j'aime pas trop cette technique, de plus, ça ne change pas le problème : où suis-je par rapport aux fichiers include. Faire un set include path plutot que de rajouter une constante c'est ... pareil. Sauf que : 1) ça modifie les paramètres php (et moi j'évite car == risques incompatibilité serveur comme ini_set() ) 2) Je préfère que tout soit par rapport au dossier que je définie. Là, on aura les include d'un coté, et les fopen d'un autre, et moi ça m'embrouille !! Mais je ne connaissais pas cette fonction alors j'ai appris qqchose :)

ViPHP
ViPHP | 5462 Messages

25 mars 2010, 17:25

c'est qui se fait quand on include un framework (exemple ZF)

library
Zend
Test.php


t'inclue la lib dans le path

et partout tu feras

require 'Zend/Test.php';

et si le Test.php a aussi un require ca sera toujours en partant du dossier Zend

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

25 mars 2010, 17:28

C'est pas parce que Zend le fait que c'est forcément super ;)

En tout cas, en ce qui me concerne, et malgré le cout en performance, je préfère l'autoloading.
Certes, il reste le soucis des chemins relatifs, mais les classes sont incluses de manière transparentes, et uniquement lorsque c'est nécessaire. Et ça, j'aime ;)
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

ViPHP
ViPHP | 5462 Messages

25 mars 2010, 17:29

ouai c'etait en exemple, Doctrine utilise l'autoload