Phing, le port de Ant (java) en PHP, propose des tasks (balises xml) permettant d'exécuter des classes PHPUnit (tests unitaires en PHP). La version stable de Phing n'est maintenant plus compatible avec la dernière version stable de PHPUnit (3.4.3 actuellement) voir avec la branche 3.4.x, et on obtient l'erreur :
[PHP Error] require_once(PHPUnit/Util/Log/XML.php): failed to open stream: No such file or directory [line 22 of C:\Program Files\PHP\PEAR\phing\tasks\ext\phpunit\phpunit3\XMLPHPUnit3ResultFormatter.php]
Voici une piste pour y remédier :
Commentaires récents
Tres bien presente! :)
Juste une remarque :
"$adapter = new CsvAdapter;
$adapter->setFile('villes.csv');"
-> Visiblement la methode setFile a ete oubliee dans l'implementation de l'adapter.
De la meme maniere j'ajouterais une methode setTable() a la classe DatabaseAdapter, ca rendrait ces 2 adapters encore plus versatiles!
En tout cas merci pour le post!
Ah oui je confirme, ne jamais utiliser Exception car PHPUnit lui même les attrape.
De manière générale utiliser Exception n'est pas correct de toute manière ;-)
$this->setExpectedException('MonException'); est aussi possible depuis un test.
Hello, merci pour cet article.
Une petite alternative : personnellement je met un nom de domaine comme nom de sections pour mes fichiers .ini de configuration.
Coté applicatif je detecte le domaine utilisé et je charge la configuration correspondante.
Ca permet à la fois de gérer les environnements de développements différents et également de mettre des paramètres spécifiques à certains domaines (ex: locale par défaut fr_FR pour example.fr et en_Us pour example.com).
Pour info, pour gérer cette problématique dans symfony on a les outils suivants :
http://www.symfony-project.org/book...
Il suffisait d'y penser , merci pour cette info :-)
C'est typiquement le genre de syntaxe dont on est très friand dans Copix :-)
Il faut avouer que cela simplifie l'écriture.... par contre on se retrouve vite avec des syntaxes compact dont il faut connaître la signification :-)
_dao ('MaTable')->findBy (
_daoSp ()->addCondition ('champ', '=', $valeur)
->addCondition ('champ2', '=', $valeur2)
->orderBy ('champ3')
)
Ce qui ici signifie : Je vais récupérer dans ma table "MaTable", grâce à un "Data Access Object", les enregistrement qui correspondent aux paramètres de recherches (daoSP = Data Access Object Search Params) ....
Le plus proche de l'exemple serait la fabrique de classe, utilisée de la sorte :
_class ('classId')
...qui retourne un new 'ClassId' (en plus d'inclure le fichier en question grâce à un système d'autoload).
J'aime assez aussi la possibilité de faire un raccourcis pour obtenir des singletons de ces objets, avec par exemple
_ioClass ('classId');// (instance of class) qui retournera systématiquement la même instance de la classe 'classId'.
En tout cas c'est sûr, le nested call de PHP 5 est pour moi une grande nouveauté par rapport à la version 4 :-)
Merci beaucoup pour ce petit billet très instructif ;)
Pour les tests d'IHM: selenium
Pour les session, perso je fais ça avec un petit curl en ligne de commande. Basic, mais aide parfois
Joli :)
Que pense-tu d'APC ou memcached, pour le coup?
Mais comment n'y ai je pas pensé avant ?
Cela fera certainement l'objet d'un ou plusieurs autres articles ;) j'ai un penchant pour APC, que j'active systématiquement en production.
1/ Ok !
2/ Ok mais ça c'est de l'utopie ^^
3/ Ok mais je préfère le commit atomique à chaque modification mineure
4/ Ok !
5/ Ok mais pas toujours faisable. La capitalisation du code n'est pas toujours possible en fonction des spécificités de chaque projet.
6/ Tests fonctionnels ou unitaires ? Dans l'idéal il faudrait les deux :)
7/ Ok !
8/ Tu entends quoi par là ?
9/ 80 c'est presque trop. Dans la plupart des cas, on peut s'en tirer avec une trentaine / cinquantaine de lignes.
10/ Toujours :)
Tu as oublié un commandement important :
11/ Les commentaires PHPDoc tu utiliseras et ton code, intelligemment et efficacement, tu commenteras.
s/du développeur PHP/du développeur/
Pareil que Hugo, j'ai tendance à préférer les commits atomique.
1° C'est plus facile à "revert"
2° Ca oblige le développeur à travailler sur des micro blocs testés
Disons que c'est des bonnes pratiques pour tout codeur en général, pas spécialement PHP (du coup ok avec Bast: s/du développeur PHP/du développeur/ )
et c'est un peu trop orienté TDD: après tout, on est pas OBLIGE d'en faire, non?
@Gab : on est pas obligé de faire du TDD, par contre les tests unitaires c'est quand même un incontournable si tu veux développer de la qualité. TDD t'apporte la rigueur, la systématisation, la démarche, le cadre, l'assurance, la sérennité... ce serait dommage de passer à côté, non ? ;)
Ca fait un paquet de temps que je cherchais ce qui me dérangeait dans le TDD, et j'ai enfin trouvé. Pas que je le refuse complètement, mais un truc me turlupinait, et j'ai mis le doigts dessus: quand je développe, j'aime bien tester plein de trucs (méthodes différentes pour faire la même chose). Récemment, par exemple, j'ai utilisé memcache pour cacher mes pages, puis APC, puis re-memcache, et là je mets des smarty dedans (d'où plus besoin de memcache).
Or, si je passe mon temps à faire du test, je vais tester un truc qui en fait va disparaître au gré de mes idées, d'où frustration et perte de temps.
Où est la faille?
On peut aussi utiliser un système de patch: tu fais une lignée de code 'souche', et 2 stocks de patch pour la spécialiser.
Ca évite les switch interne avec des constantes.
Je me demande aussi si cette technique ne pourrait pas être jouable avec darcs (qui commit des patch, lui)
Pourquoi pas utiliser memcache?
Ton objet serait stocké dedans par l'appli, et recraché par le script PHP. Tu évite ainsi des accès disques.
Il existe aussi le plugin "modify headers" qui permet de (comme son nom l'indique) modifier les headers.
Tu ne veux pas faire une usine à gaz, mais tu t'embarques avec phing, phar et un fichier de config. XML.
OK, tu n'as qu'un seul script PHP à maintenir, mais par contre tu te retrouves avec X fichiers de config. XML.
Je pense qu'un script PHP pour chaque couple application/environnement serait une solution plus simple et donc plus efficace.
Effectivement on aurait pu se passer de Phar et Phing en ayant par exemple 1 fichier de script générique, n fichiers de configuration. Ca m'embête vis a vis du processus de livraison pour mes équipes de production, mais c'est tout a fait faisable et pertinent.
Par contre, faire 1 script spécifique par couple application/environnement, ca oblige à dupliquer la partie commune (affichage du résultats, code des tests de vérifications...) ce qui multiplie les erreurs possibles et rend plus difficile la maintenance. J'avoue cependant que c'est souvent ce que l'on rencontre dans les projets, car ca reste la solution la plus simple.
Par contre, qui/quoi garantit que ton / tes scripts de vérification ne contiennent pas d'erreurs et qu'il te dise que la connexion mysql testée est en succès alors que c'est faux ? Il peut être nécessaire d'ajouter des tests unitaires pour vérifier que les tests de santé que tu réalises sont bien implémentés et fonctionnent tel que prévu. Si tu as plusieurs scripts avec du code dupliqué, tu auras des tests dupliqués aussi, ce qui n'est pas optimal et une vraie contrainte pour les développeurs...
Il existe donc plusieurs méthodes, à choisir en fonction des besoins et des contraintes. De mon côté, tous les développements PHP sont accompagnés de tests unitaires cela à donc un impact sur l'architecture du code et notamment la mutualisation des méthodes/fonctions. D'autre part, j'évolue déjà dans un environnement Phing, la cout de mise en oeuvre est donc limité pour ma part.
En tout cas merci pour ton retour qui est une critique très intéressante !
Aller, j'enfonce le clou : tu dis que le script ne doit pas dépendre d'une bibliothèque. Mais il faut avoir installé l'extension phar sur toutes les becanes pour que ta solution fonctionne !
;-)
De mémoire (à vérifier), un phar est exécutable par PHP même si l'extension Phar n'est pas activé (c'est un des intérêts). Exemple : quand tu installes PHP sur ta machine en local (par exemple sous windows), tu peut ajouter le support de Pear, pour cela tu dois exécuter le fichier go-pear.phar (de mémoire encore) qui fonctionne même si ton installation de php est standard (je ne crois pas qu'avant la version 5.3 l'extension phar soit activée par défaut).
Depuis la 5.3, l'extension phar en native (de mémoire encore).
Je pense donc que ca ne pose pas de problème, mais dès que j'ai 5 minutes je teste, si ca ne marche pas je vous le dis.
Dans l'hypothèse ou ca ne fonctionnerait pas, ton script serait en erreur (il ne se lancerait pas), et tu le verrais tout de suite à son exécution, ce n'est donc pas une erreur silencieuse, et tu peux y remédier tout de suite. Le niveau de criticité me semble donc assez bas à partir du moment ou tu peux ajouter des extensions sur le serveur en fonction des besoins.
Il est probable, bien que l'extension phar ne soit pas nécessaire pour exécuter un phar, que les extensions de compression le soit tu as compressé ton phar (à vérifier). Mais je ne vois pas l'intérêt de compresser le phar dans notre cas.
en effet, l'utilisation des transactions mysql avec un bloc try/catch est la meilleure solution, c'est celle que j'utilise aussi
Dans l'idéal, il faut vérifier toutes les valeurs de retour de chaque fonction utilisée, que ce soit pour les bases de données, la manipulation du système de fichier... J'utilise PDO pour mes connexions à la BDD, ce qui me permet de profiter des Exceptions pour gérer les erreurs liées à la base de données.
En sachant que l'utilisation des transactions en MySQL n'est pas toujours portable, cela dépend du moteur utilisé (ça marche pour les tables en InnoDB mais pas en MyISAM)
Vous avez bien assuré sur le stand, malgré la concurrence de Python (AFPY) et Ruby On Rails :)
Pourquoi ne pas utiliser les exceptions définies dans la SPL (http://fr.php.net/manual/fr/spl.exc...) ?
Et à la limite :
class MaSuperException extends InvalidArgumentException { }
Cette approche a l'avantage selon moi de pouvoir définir un traitement différent selon les types d'erreurs rencontrés de façon générique, qu'elles soient levées par le langage ou par l'utilisateur (en tenant des journaux avec des niveaux de sévérité différents selon les types d'exceptions rencontrés).
J'utilise ce mécanisme en complément de la classe ErrorException (buggée en ce moment je crois) pour gérer tous les problèmes pouvant être rencontrés durant l'exécution des scripts.
Tu as tout a fait raison, l'utilisation des exceptions de la SPL est une bonne pratique.
Jusqu'à la version 5.3 (non compris), l'extension, packagée avec PHP par défaut, pouvait être désactivée. Depuis la 5.3 elle ne peut plus être désactivé, il n'y a donc plus d'excuse pour ne pas l'utiliser.
Cela ne vous empêche pas de rajouter certains type d'exceptions non prévus dans la SPL, avec parcimonie !
Si le concept de packages pour PHP vous intéresse, jetez un coup d'oeil à http://webappkit.net
Il s'agit un système de paquets pour PHP, qui facilite la gestion des dépendances entre librairies et offre également une interface d'administration permettant de visualiser le tout et d'executer les tests unitaires.
Et bien sûr, c'est open source et quelques librairies sont déjà fournies.
Merci pour l'information sur webappkit !
Je testerais dès que possible.
Quelle est la particularité par rapport au système de gestion de dépendances et de packaging de PEAR ?
Olivier
PEAR s'installe au niveau système et ne gère que des librairies. Webappkit s'installe au niveau application web (simple dezippage), de telle manière qu'une appli construite sur Webappkit peut être entièrement installée via FTP.
De même, l'interface d'administration est une page web qui à terme permettra d'installer les librairies par upload de fichier zip. Pour l'instant elle permet de visualiser les tests, vérifier les dépendances, l'intégrité des paquets etc.
En outre, les paquets sont accessibles sous forme d'objets dont la classe est extensible, et auquels on peut adjoindre des objets services issus d'autres paquets. Un paquet peut ainsi contenir d'autres types de ressource que des scripts PHP, tel que des templates, etc. Ceci permet d'avoir une application complete sous forme de paquet.
Je ferai une nouvelle release (0.13) prochainement (une a deux semaines).
Pour gérer le problème de la base de données, je vois deux solutions qui s'intègrent dans le script de livraison de l'appli :
* Sauvegarde complète de la base que l'on archive dans /opt/mon-appli-2.1
* Versioning de la base de données (non testé) : une base par version du code.
Mais en cas de rollback rest le problème du différentiel de données (nécessite une anticipation).
PS: A noter que les fichiers générés par l'application doivent être géré hors du "code"
J'utilise Subversion pour gérer le déploiement de mes releases en taggant celles-ci dans mon repository.
Ainsi je n'ai qu'à faire un svn export du tag correspondant à la release que je veux déployer. Idem pour revenir en arrière.
@Jean-Sébastien: concernant le problème de différentiel des données en cas de rollback, il y a peut être une piste du côté du mécanisme de réplication des bases de données. Notamment MySQL Replication Mechanism permet de répliquer toutes les requêtes effectuées à partir d'un instant (numéro de version de la base) sur une autre base de données (i.e. un autre serveur). Il suffirait alors de noter le numéro de version quand on fait une mise en production, et lorsqu'on fait un rollback d'activer le mécanisme de réplication sur un nouveau serveur/base de données et faire répliquer toutes les requêtes le numéro de révision et maintenant. A creuser (déjà testé sur une plateforme mais pas dans ce contexte).
@Ladenise: svn export n'est pas forcément "rapide", en effet si ton projet contient des milliers de fichiers, la durée du svn export peut être non négligeable (plusieurs minutes) et rendre indisponible ton application, voir pire, pendant le svn export, si tu n'as pas désactivé l'accès à l'appli il peut y avoir un comportement imprévu si certains fichiers sont exportés mais pas tous. D'autre part, comme l'indique Jean-Sébastien, il faut forcément coupler avec un autre mécanisme pour gérer le rollback de la base de données car svn export ne peut le faire (peut être avec un script côté serveur svn, car c'est possible de déclencher un script sur une action svn, mais si le serveur svn n'accède pas à la prod...). La solution svn export est une solution simple cependant.
Je ne pense pas que dirname( __FILE__ ) remplace le define( 'ROOT' , <dir> ).
L'un n'a rien avoir avec l'autre.
L'utilisation d'une constante qui pointe sur la racine est très utile : pour former un path sans avoir de ROOT, on doit jongler avec les '/..' etc.
L'inclusion dans les autoloader de class (spl_autoload_register), de déplacement au sein du filesystem du code, etc., sont entièrement facilités par une constante "ROOT". Les chemins relatifs portent trop souvent à confusion.
De plus, le fait de définir le ROOT à partir de dirname( __FILE__ ) fait qu'il est absurde de dire une bêtise comme :
"Plus besoin de tenir un fichier de configuration avec des define qui est a modifié à chaque installation."
Encore une fois, l'un et l'autre sont deux choses différentes.
De plus, il aurait été intéressant de préciser qu'à partir de la version 5.3, la constante __DIR__ offre l'équivalent d'un dirname( __FILE__ );
@avetis.kazarian: tout est histoire de pratique, il n'y pas de bonnes et mauvaises pratiques universelles, cependant certaines pratiques sont plus adaptées que d'autres dans certaines situations.
Un fichier qui utilise le principe de dirname(__FILE__) pour inclure ses dépendances, est potentiellement utilisable directement par une autre application ou script, si il nécessite la présence de constantes (ex: ROOT) alors il faudra au préalable définir ces constantes avant d'utiliser ce fichier dans une autre application.
Effectivement, cela n'a pas de réelle importance lorsque l'on développe une application autonome, mais en prend lorsque l'on décide de rendre potentiellement mutualisable à toutes nos applications/scripts tous les développements que nous réalisons.
Attention aux "dépendances" implicites de notre code à des éléments extérieurs (define, variable globales, fichiers de configuration...) ils rendent difficilement testable ou utilisable dans un autre contexte notre code.
Merci pour la précision sur la constante __DIR__ en PHP 5.3, pour toutes les applications legacy des S.I français (et autres !) qui ne pourront pas bénéficier de la 5.3 avant quelques mois voir années, dirname(__FILE__) reste utilisable en attendant...
J'utilise Komodo edit. J'ajoute les doc block à la main, mais ceux ci sont ensuite supportés par l'autocompletion ce qui est une bonne incitation à leur utilisation :)
J'avoue que je n'utilise pas trop le chainage des appels, le poids de ma pratique de PHP4 sans doute. Et généralement mes setters renvoient un booleen.
Même chose et même évolution que toi.
Au début c'était cool l'autocomplétion puis c'est devenu une vrai méthode de travail. Les appels chaînés sont devenu une religion...
Ce qui m'amène à regretter que les types scalaire de php ne soit pas objet et qu'on ai toujours les str... fonctions, les array... fonctions etc...
Attention ! Il ne faut pas mélanger les "doc block" (autrement dit PHPDoc) et les "annotations"; ce sont deux choses entièrement différentes dans Eclipse.
Ce que vous présentez-là sont les blocs de commentaire à la JavaDoc (pour PHP on dit PHPDoc). Alors que les annotations sont un ensemble de mises en relief du code que propose Eclipse. On trouve les options d'annotations dans General > Editors > Text Editors > Annotations. Elles permettent notamment avec PDT par exemple, d'avoir pour une variable toutes les occurrences surlignées en une couleur (lorsque le curseur se trouve dessus).
Il y a de très nombreux paramètres et on s'y perd vite, mais une bonne utilisation de ceux-ci permet de gagner beaucoup de temps.
Je recommande à tous ceux qui travaillent sur un fond noir de passer par là pour les problèmes de couleurs (light/light).
En passant :
"public function getInstance" n'est pas déclarée "static" ;)
@avetis: merci de la précision sur une des nombreuses fonctionnalités d'Eclipse ;)
Par contre, en PHP le terme Annotations est aussi utilisé pour ce type d'artefact, cf http://www.slideshare.net/stubbles/declarative-development-using-annotations-in-php, ou le package PEAR PHP_Annotation, entre autre.
J'en conviens il s'agit plus de doc bloc façon xdoclet (de mémoire en Java) plutôt que de réelle annotation à la sauce Java. Mais c'est un compromis déjà efficace à leur actuelle.
Merci pour la coquille sur le public final static getInstance, c'est corrigé.
Je ne suis pas un expert avec les patterns, pourrais-tu développer cette phrase ?
"je crée quasi systématiquement des factories pour éviter de passer par une variable inutile"
Dans un nouveau post éventuellement.
@Moosh: plus simplement (j'espère ;) ) :
$o = new MaClasse();
$o->maMethod1();
$o->maMethod2();
$resultat = $o->maMethod3();
Dans ce cas là, tu réalises un enchainement de méthodes qui appartiennent toutes à l'objet $o. La variable $o finalement ne te sert pas à grand chose si ce n'est de pouvoir appeller les méthodes les unes à la suite des autres. Pour factoriser tu pourrais faire :
$o = new MaClasse();
$resultat =
$o->maMethod1()
->maMethod2()
->maMethod3();
C'est déjà un peu mieux (on peut tout mettre sur une ligne si on veut), par contre on se rend compte que la variable $o ne sert à rien finalment car elle n'est plus jamais utilisée (dans la suite du script). Du coup tu pollue ton script avec des variable qui ne sont pas utilier (et aussi l'espace mémoire).
L'idée de la factory c'est finalement de faire une méthode static qui permettra d'éviter de mettre le "new MaClasse()" dans une variable :
$resultat = MaClasse::creeObjet()->maMethod1()->maMethod2()->maMethod3();Si tu as pris soin de mettre de nom de classe explicites, des noms de méthodes assez court et parlant, tes scripts peuvent être plus concis et plus parlant (tu peux aussi mettre sur plusieurs lignes).
La méthode creeObjet() peut aussi prendre un paramètre (c'est tout l'intérêt d'une factory), on sait qu'on fait souvent l'enchainement maMethod1() et maMethod2 dans notre code, et qu'en suite on a besoin de l'objet. On peut alors faire :
class MaClasse {
...
/**
* Fait quelquechose
*
* @return MaClasse
*/
public function maMethod1() {
...
return $this;
}
/**
* Fait quelquechose
*
* @return MaClasse
*/
public function maMethod2() {
...
return $this;
}
/**
* Fait quelquechose
*
* @return string
*/
public function maMethod3() {
...
return "un resultat quelconque ici";
}
/**
* Retourne une instance de la classe
*
* @param string $comment optionnel, quel type d'instance retourner ? Si null, une instance vierge, si 'm1_et_m2' => l'instance aura déjà eu maMethod1() et maMethod2() d'appellées
*
* @return MaClasse
*/
public final static function creeObjet($comment=null) {
$o = new self;
if (null !== $comment && 'm1_et_m2' === $comment) {
$o->maMethod1()->maMethod2();
}
return $o;
}
...
}
$result = MaClasse::creeObjet('m1_et_m2')->maMethod3();
Ma remarque voulais simplement dire qu'en utilisant ce principe de factory (qui prennent un paramètre éventuellement) je peux éviter de faire le new moi-même et éviter de stocker l'objet dans une variable (si combiné avec des 'return $this' dans chacune des maMethodX())
J'espère que c'est un peu plus claire, sinon n'hésites pas à demander des précis / rectifications
v0.2.0 releasée !
Nouvelle feature : calcul des ratios de taille, nombre de fichier et nombre de lignes pour des patterns de noms de fichiers donnés :
ex: "je veux connaitre la proportion de fichiers PHP qui sont situés dans le répertoire tests/ par rapport à ceux qui sont dans le répertoire library/"
Voilà un outil intéressant que j'ai hâte de tester.
Sur le même sujet, l'outil phploc de Sebastien Bergmann qui permet de calculer des informations similaires mais plus basées sur le nombre de lignes pas les ratios (que l'on peut calculer ensuite vous me direz).
Ca sert plutôt comme outils 'a posteriori', non? Par exemple pour comme indicateurs.
Intéressant comme outil.
Par contre les mesures de temps me surprennent : PHP se targue d'avoir améliorer les performances de 10 à 20% sur les versions 5.x et ca ne se reflète pas dans tes chiffres.
@jean-sebastien: Bonne remarque, effectivement de prime abord j'ai été surpris par les temps d'exécution qui s'allongent sur les versions plus récentes de PHP. Je n'ai pas investigué plus sur le sujet mais mon hypothèse est que cela vient du mode d'exécution. J'utilise l'exécutable php en ligne de commande pour chaque exécution de fonction, il est probable que l'overhead de chargement de php en mode CLI soit plus important sur les versions récentes de PHP, ce qui n'est probablement pas le cas en mode Module sous Apache (chargement au démarrage d'Apache). Je ne vois pour l'instant que cette seule explication. Cela rend effectivement un peu moins pertinent la mesure des temps d'exécution, qui du coup sont aussi fonction de la charge CPU/Machine (puisqu'un nouveau process est exécuté), donc peuvent être pollué de façon transparente. En appuyant sur F5 plusieurs on peut notamment avoir la tendance tout de même ;). Pour aller plus loin, il peut être envisageable que je retranche le temps de chargement PHP et que je mette uniquement le temps d'exécution, d'ailleurs ce serait plus pertinent, d'ailleurs je viens de faire la modification ;)
Pour moi, je travaille souvent sur Netbeans 6.5 grâce à ses fonctionnalités qui couvrent tous les besoins d'un developpeur professionnel
Bonjour,
Merci pour le tutotial. Par curiosité.
Hormis les paquets pear, je ne me rappel pas avoir été embeté par l'installation de hudson en suivant la procédure suivante.
http://weblogs.java.net/blog/kohsuk...
et pourquoi ajouter lighthttpd ?
@senjy : il s'agit d'une installation sur un serveur dédié à hudson, pas d'applications web sur ce serveur, j'ai jugé que lighttpd serait suffisant et plus léger que apache, sachant que le serveur n'est pas une bête de course. Mais apache est un bon candidat sinon, bien sûr. Concernant le tutorial, votre lien est cassé, je pense qu'il s'agit de http://weblogs.java.net/blog/kohsuke/, je me suis inspiré de certains articles de Kohsuke mais j'avoue ne pas avoir trop cherché de tutoriaux tout fait sur l'installation, étant donné que j'avais la spécificité PHP / Lighttpd / OpenJDK. Merci tout de même pour le pointeur.
Une autre bonne habitude pour éviter ce genre de problème est d'indiquer le type de l'objet attendu, lorsque l'argument est un objet :
function foo(anObject $objet = null) {
...
}
Cette méthode évite bien des problèmes sans surcharge de code dans le corps de la fonction, vu que la vérification est prise en charge par le moteur de php nativement.
Cepdendant, vu que les types de base de PHP ne sont pas "objet" (sic), pour ces derniers, ta technique est la plus appropriée, à part dans les cas des tableaux ou la mienne fonctionne également (encore une aberration de PHP :)) :
function foo(array $array = null) {
...
}
Merci pour ce build, c'est tres interessant.
Est ce que c'est possible d'avoir quelques capture d'ecran du résultat obtenu ?
Je ne pensais pas qu'en 2009 on pouvait encore se poser cette question. La réponse est assez évidente il me semble.
Superbe analyse.
Voilà enfin les bonnes questions qui sont posées.
Pas la POO pour la POO. Autrement dit tous les Framework ne se valent pas selon mes besoins/projet/compétences/tps mise en oeuvre.
On peut facilement imaginer utiliser partiellement un framework pour la partie qui nous apporte réellement de la valeur ajoutée. Les modules trop lourds du framework (du point de vue projet) peuvent alors être remplacé par une méthodologie maison potentiellement avec une partie procédurale (pas de tabous) en plus de la POO bien sur inévitable.
Il faut donc privilégier les framework modulaires
Les bonnes questions sont posées.
Je développe plutôt en procédurale, mais depuis quelques temps je passe de plus en plus au POO. J'utilise un Framework POO : Kohana. (une base de Code Igniter, mais uniquement PHP 5 et Objet). Si on souhaite suivre l'évolution de PHP, resté en 100% procédurale revient a une limitation assès déconcertante.
Je suis en train d'essayer, mais après avoir installé PHPUnitLaucher et les outils de dev Java, "Run As... Junit test" m'ouvre la console pour me dire "May be port 8888 in used, try another". Ou parfois il ne dit rien.
J'avoue que je ne sais pas quoi passer à -DphpunitArgs...
Ben en fait le channel pear.phppro.fr
ne réponds plus
> Subversion (ou CVS, même si je conseille de l'abandonner au profit de CVS)
Je suppose que tu voulais parler de Subversion et non de CVS la seconde fois. ;)
Plutot qu'écrire du code pour les Mock, PHPUnit a développé un système de bouchon assez puissant.
Voir la fonction getMock
Justement à propos de :
il manque un test (non unitaire cette fois-ci) qui nous permet de vérifier
Quelle serait sa forme idéale ? Implémentation, méthode, utilisation ?
@Bruno: un début de réponse dans mon post : http://blog.phppro.fr/?post/2009/08/14/Tests-d-integration-quezako
@jsh : tout à fait d'accord avec la présence de cette fonctionnalité intéressante de PHPUnit, pour ma part je préfère réaliser mes mocks moi même car sinon je ne peux pas utiliser de mock en dehors de mes tests unitaires, hors cela peut être intéressant d'utiliser un mock à certains moment du développement (au début du développement d'un webservices par exemple), ou bien dans un autre contexte d'appel que phpunit. D'autre part, je trouve le mécanisme de gestion de la pile d'appel assez verbeux à écrire pour le mock, et je préfère la notion de pile à la "addExpectedResult", plus brute mais plus simple. Mais la fonctionnalité reste intéressante ;)
@Bruno : il s'agit d'une indisponibilité temporaire, cela devrait être rétabli fin aôut (réinstallation de mon serveur PEAR :( ), En attendant tu peux télécharger le tarball compatible PEAR sur Google Code à l'adresse http://code.google.com/p/phpcoderatio/downloads/list, puis faire un :
$ pear install phpcr-0.2.0.tgz
@Cédric: je t'invite à ouvrir un ticket sur http://code.google.com/p/phpunit4eclipse/issues/list, ou à contacter Bertrand Paquet le développeur "bertrand point paquet at gmail point com"
@Senjy : Quels types de captures d'écrans souhaites-tu ?
merci pour cette article, c'est intéressant de trouver des sujets qui touche le monde professionel en plus autour de PHP. Ce qui est rare.
Mais c'est vrai qu'avoir des exemples concret c'est encore mieux. aussi je suis preneur
petite question sur un détail constaté :
"Exemple dans le fichier contexts/@common.php (inclus par tous les fichiers de mon application) :"
à quoi sert ce @ dans le nom de fichier ?
Classement ? comportement magique ?
"Le travail fait n'est jamais perdu", dixit un collègue ;)
Tu dégage le code, mais les idées que tu as mis en oeuvre pour l'écrire reste d'une manière ou d'une autre dans ta tête.
Exactement la même chose. Votre réponse est parfaite. On trouve si souvent des méthode commentées dans des classes sans savoir qui les a écrites, qui les a commentées et pourquoi... La gestion des version est là pour cela.
Quand au wiki c'est effectivement un point intéressant pour peu que l'on en ai un sous la main.
On dispose de solutions pour garder des traces de changements (svn par exemple), par contre j'ai toujours pas trouvé de solution efficace permettant de "se souvenir" de ce qui a été fait.
Vous est-il déjà arrivé de récupérer un vieux code dont vous n'aviez la connaissance ni au moment de son écriture, ni du nettoyage ?
Je suis persuadé que le seul cas où ça se produit c'est le coup du collègue qui dit "ya machin qui avait codé quelque chose de similaire, regarde le dépot".
@Raph: bonne remarque, effectivement cela arrive régulièrement de commencer à développer une snippet pour nos propres besoins et de se rendre compte que quelque chose de similaire a déjà été développé dans l'équipe (par le passé, ou ... en parallèle !). Pour tenter d'endiguer ce problème je propose en règle général un ensemble de pratiques simples à mes développeurs: 1/ regarder si un "service" (par exemple technique) n'existe pas déjà dans l'API projet, 2/ ne jamais copier / coller mais plutot déplacer du code à un endroit central et l'utiliser à plusieurs endroits, 3/ toujours développer la solution la plus simple possible pour répondre au besoin du moment, entres autres.
Eclipse et Zend Studio propose des "Code Gallery", je pense que c'est aussi une piste pour retrouver du code déjà développer en ayant une démarche "search first, code after".
j'aime bien cette idée de revue partielle de code, je suis cependant un peu réticent à l'idée de laisser le développeur choisir quel fragment de code sélectionner, craignant un peu la dissimulation du code "baclé" et l'envoi d'un code nettoyé, surtout si la personne relisant ce code est un n+1... Je préfère l'idée d'un envoi d'une liste des fonctionnalités développées et une revue de code "au hasard" ou d'instinct sur les fonctionnalités critiques.
L'idée de la revue croisée est une bonne alternative, (j'en avais discuté avec Damien Seguy lors d'une formation), bien encadrée, elle permet de créer une émulsion entre les développeurs.
Merci, c'est une présentation très claire.
Tu parles des tests fonctionnels avec Fitnesse et PHPSlim/PHPFit. Ca fait longtemps que j'en entend parler mais n'ai jamais eu l'occasion de les utiliser sur de vrais projets. Tu aurais des cas concrets de mise en œuvre à présenter ?
@clochix: je prévois un ou plusieurs articles sur le sujet TDR (Fitnesse / GreenPepper) dans les prochaines semaines, keep in touch ;)
Complément d'information posté sur le blog de Clochix (http://www.clochix.net/post/2009/09...) concernant l'utilisation des fonctionnalité Mock de PHPUnit:
Pour ma part, j'évite de l'utiliser (i.e. la fonctionnalité Mock de PHPUnit) car je souhaite rester indépendant d'un quelconque framework lors de mon développement.
Les fonctionnalités Mock de PHPUnit sont très intéressantes, elles ont cependant de mon point de vue un défaut majeure dans l'utilisation que je fais des mocks. En effet, lorsque je développe j'utilise la version "mock" de mes classes (adapter) dans mon code tant que je n'ai pas développé la version native (standard). Cela me permet de prototyper / présenter rapidement les fonctionnalités "statiques" de mes développements et de "débrancher" lorsque je suis prêt le mock pour mettre la vraie implémentation (imaginez que je développe un webservice et que je doive rapidement fournir une version de mon webservice pour des consommateurs qui seraient "impatients"). Le problème avec le framework PHPUnit est qu'il n'est pas adapté a priori pour une utilisation en dehors des tests unitaires.
autre part les mocks peuvent être utiles dans d'autres cas encore que les tests unitaires et celui que je décris, par exemple certains tests d'intégration qui porte sur d'autres zones du code... même remarque dans ce cas.
Et vous quels sont vos pratiques pour mettre en place des bouchons dans les cas autres que les tests unitaires ?
J'utilise ext/inclued.
Qu'as-tu utilisé comme outils ?
@jpauli: Je ne connaissais pas ext/inclued, je pense qu'il est très similaire à mon outil, qui par contre est un outil d'analyse statique (pas au runtime). J'ai moi même développé l'outil qui a servi à généré ce graphe. L'algorithmique est simple : analyser toutes les références à des classes / inclusions autres que la classe courante, c'est à dire recenser les extends, implements, includes, appels statiques, instanciations, ... Mon problème se situe plutôt au niveau de la réprésentation graphique, j'ai actuellement fait le même choix basique que ext/inclued, à savoir l'utilisation de graphviz/dot, qui fonctionne plutôt bien, mais mes conclusions sont que pour profiter de toutes la richesse de ce type de graphe/informations il est nécessaire d'utiliser une représentation graphique "vivante" permettant de parcourir en temps réel les dépendances, notamment lorsqu'il s'agit du graphe de dépendances de ZF (plusieurs centaines de noeuds)... Pour l'instant j'ai vu une librairie Flash qui serait parfaite pour ça, Constellation Roamer de Asterisq (www.asterisq.com), mais le prix de la licence ma un peu refroidi, pour l'instant...
Je compte mettre en open source le code de l'outil, mais le temps me manque ces jours-ci ;)
Le temps manque ? C'est bizarre je connais bien le principe xD
Très intéréssant ton outils. Bcp de projets PEAR possèdent un parseur PHP libre basé sur les tokens (PHPDepends, PHPCPD etc...), peut-être pourra tu créer un channel pear et un composant quand tu auras le temps ? ;-)
Quoiqu'il en soit, je ne peux t'aider en ce qui concerne l'animation, mais je reste persuadé que de tels paquets existent dans le monde du libre (le contraire m'étonnerait). A chercher... :)
Bonjour,
j'ai trouvé le slide excellent. cela correspond pile poil à ce que j'aimerai mettre en place dans mon entreprise.
ce n'est pas facile mais j'y crois dur comme fer.
est-ce que tu as quelques conseils sur la manière de procéder ?
merci d'avances
@jacko972: envoie moi un email sur contact at phppro point fr en me décrivant ton contexte, tes problématiques et tes questions
Salut, merci pour cet article intéressant.
Pour la visualisation dynamique, ça me fait penser à un outils Java (désolé...) très intéressant pour parcourir le modèle d'une BDD : jailer. Il se base sur une librairie graphique (prefuse). C'est du Java certes, mais il y a surement des idées à puiser ;)
A+
Merci pour l'analyse, effectivement il serait bien de pouvoir greffer un outil similaire à celui ci à une trace d'exécution temps réel.
Pourquoi pas à base des traces générées par xdebug, que j'analyse avec kcachegrind pour le moment. Au niveau des bibliothèques qui permettent de faire ça, je pense à Infovis(http://thejit.org/demos/).
Sinon, une bonne manière de comprendre et d'analyser les dépendances de notre code, c'est d'utiliser l'inversion de contrôle, et de coupler le tout avec un injecteur de dépendances, pour générer directement un schéma !
C'est amusant, j'avais commencé aussi à coder un analyseur de dépendances mais pas du tout dans ce but. Le mien était de pouvoir extraire seulement le nécessaire d'une librairie ou d'un framework.
@alexis: déjà essayer InfoVis (JS) mais pas satisfait pour ce besoin. Mes conclusions sont que seul flash / flex offre une ergonomie suffisante dans mon cas (fluidité, usabilité...).
@evoilliot: jailer semble trop spécifique aux base de données effectivement. J'ai déjà regardé du côté du projet Prefuse, qui a une implémentation exceptionnelle en Flex/Flash (Flare Project). C'est d'ailleurs celle qui est en top de ma liste. Le coup d'intégration de la librairie est cependant assez élevé (pas mal de développement ActionScript), je n'ai malheureusement pas assez de temps pour améliorer ma Proof of Concept sous Flex Builder :(
@jean-marc: peut être des bonnes idées à prendre dans ton outils, il est disponible quelque part ?
@all: version open source imminente...
Respects !
Voila un outil des plus intéressants concernant l'OO.
J'utilisais PHPDepends jusqu'à présent, mais ton outil est d'ores et déja dans ma liste ;-)
Merci, c'est un article interessant pour un sujet qui est d'actualité pour moi. Comment inserer des images dans un documents docx ?
@spm: C'est un peu plus compliqué mais possible, j'utilise ce type de routine (qui contient certainement des bugs, mais qui fonctionne pour mes générations de rapports avec OpenXML) :
// parses for pics if (preg_match_all('/(.*)<\/p\:pic>/U',$content,$matches)>0) { for($i=0;$i
/U',$matches[1][$i],$matches2)>0){ $matches3 = null; if(preg_match_all('/\$\{([^\}]+)\}/',$matches2[3][0],$matches3)>0) { $matches4 = null; if(preg_match_all('/0){ $relFile = dirname($file).'/_rels/'.basename($file).'.rels'; if (true === file_exists($relFile)) { $x = simplexml_load_file($relFile); foreach($x->Relationship as $relationship){ if ((string)$relationship['Id'] === $matches4[1][0]){ $picFile = (string)$relationship['Target']; if(!$picFile) continue; $picFile = realpath(dirname($file).'/'.$picFile); if(!$picFile) continue; unlink($picFile); try { $tplPicFile = $this->parseVar($matches3[0][0],$matches3[1][0],$vars); } catch(Exception $e) { $tplPicFile = dirname(__FILE__).'/resources/no-data.png'; } copy($tplPicFile,$picFile); } } } } } } } } $content = $this->parseString($content,$vars);
Globalement, je mets le nom de la variable dans l'attribute "description" texte de l'image dans mon document openxml (par exemple dans powerpoint) puis je parse le xml du document pour remplacer les occurences des variables par les vrais images sachant que les balises xml existent déjà (puisque créé par powerpoint) sauf sont à ajouter les balises xml des resources (le fichier image complémentaire)
Sorti du contexte, ca doit être un peu rebutant par contre, je le conçois...
olivier