IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

[hardCore PHP OO] injection de dépendance/inversion de contrôle


Sujet :

Langage PHP

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2011
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2011
    Messages : 154
    Par défaut [hardCore PHP OO] injection de dépendance/inversion de contrôle
    Bonjour,

    Je souhaites revoir mes habitudes de dev, et je m’intéresse actuellement à PHPUnit.
    J'avais l'habitude d'utiliser des singletons et/ou des méthodes statiques, mais il semble que ce soit le diable, au moins pour les tests unitaires.
    Sans relancer le débat, vous confirmez?

    Donc j'ai maintenant l'occasion de me lancer dans l'injection de dépendance et l'inversion de contrôle. Je souhaiterai un outil, qui:
    -Gère l'inversion de contrôle
    -Gere les require/include
    -soit léger
    -soit peu verbeux, idéalement un truc comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $monObjet=$contexte->factory('objet')->get(25);
    Connaissez-vous un outil qui corresponde à ça, ou vaut-il mieux que je le développe moi-même?

    D'autres remarques?

    Merci,
    @+
    Piero

    J'avais ouvert cette discussion dans un autre forum, je me suis planté donc j'ai mis un lien vers celle-ci...

  2. #2
    Expert confirmé
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Par défaut
    J'avais l'habitude d'utiliser des singletons et/ou des méthodes statiques, mais il semble que ce soit le diable, au moins pour les tests unitaires.
    Douce musique à mes oreilles, c'est pas tout les jours que j'entends quelqu'un devenir raisonnable.

    Blague à part c'est tout à fait vrai, les composants qui utilisent massivement les singletons et les membres statiques sont par nature difficiles voire impossible à tester car ils agissent comme un ensemble et non comme des briques remplaçables. On ne peut donc pas les mocker, ce qui rends le test pratiquement impossible.

    J'ai publié sur mon site un article sur l'injection de dépendances et la programmation orientée composants en général, je t'invite à y jeter un oeil.

    Par contre la gestion de l'inclusion automatique et l'injection de composants sont deux aspects séparés.

    Pour l'injection de dépendances, tu peux utiliser Pimple, c'est simple, léger mais puissant malgré tout (surtout son système d'abstract-factory à base de closures !)

    Pour l'autoload, utilise celui de composer en créant tes composants de sorte qu'ils soient compatibles composer. Une fois installé sur ton projet, composer t'offre nativement un autoloader puissant.

  3. #3
    Membre très actif
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2011
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2011
    Messages : 154
    Par défaut
    Citation Envoyé par Benjamin Delespierre Voir le message
    Douce musique à mes oreilles, c'est pas tout les jours que j'entends quelqu'un devenir raisonnable.

    Blague à part c'est tout à fait vrai, les composants qui utilisent massivement les singletons et les membres statiques sont par nature difficiles voire impossible à tester car ils agissent comme un ensemble et non comme des briques remplaçables.
    J'avoue qu'il m'a fallu un bon temps de réflexion avant d'en convenir! Je suis du genre têtu...

    Citation Envoyé par Benjamin Delespierre Voir le message
    On ne peut donc pas les mocker, ce qui rends le test pratiquement impossible.
    Holà, je me mocke de personne, ni d'aucun objet... Bref, je suis pas encore à l'aise avec ces termes, je débute... Mocker c'est un peu comme si on les by-pass avec un faux objet, c'est bien ça?

    Citation Envoyé par Benjamin Delespierre Voir le message
    J'ai publié sur mon site un article sur l'injection de dépendances et la programmation orientée composants en général, je t'invite à y jeter un oeil.
    J'y vais de ce pas...

    Citation Envoyé par Benjamin Delespierre Voir le message
    Par contre la gestion de l'inclusion automatique et l'injection de composants sont deux aspects séparés.
    Oui je sais, mais justement, je me demandais si il ne serait pas intéressant, de faire d'une pierre deux coups, un système "tout-en-un". Mais peut-être que je prends mes rêves pour des réalités, et qu'on ne peux pas faire "correspondre" les deux. Je dois encore y réfléchir en tout cas.

    Citation Envoyé par Benjamin Delespierre Voir le message
    Pour l'injection de dépendances, tu peux utiliser Pimple, c'est simple, léger mais puissant malgré tout (surtout son système d'abstract-factory à base de closures !)
    , j'en ai des frissons dans le dos, que des trucs que j'aime, il a l'air parfait ce truc, on pourrai pas y greffer un système d'inclusions automatiques?

    Citation Envoyé par Benjamin Delespierre Voir le message
    Pour l'autoload, utilise celui de composer en créant tes composants de sorte qu'ils soient compatibles composer. Une fois installé sur ton projet, composer t'offre nativement un autoloader puissant.
    Ok, j'y jetterai un œil, c'est light? C'est pas trop contraignant de créer des composants compatibles?

    Merci Benjamin pour ces réponses, j'aurai certainement d'autres questions ensuite...
    @+
    Piero

  4. #4
    Expert confirmé
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Par défaut
    Oui je sais, mais justement, je me demandais si il ne serait pas intéressant, de faire d'une pierre deux coups, un système "tout-en-un". Mais peut-être que je prends mes rêves pour des réalités, et qu'on ne peux pas faire "correspondre" les deux. Je dois encore y réfléchir en tout cas.
    Le système tout-en-un est à l'opposé de l'approche orientée composant.

    BTW, l'autoload c'est vraiment vraiment simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <?php
     
    register_autoload_function(function ($classname) {
      return include "{$classname}.php";
    });
    et c'est tout. Si tes composants / librairies sont dans l'include path, leur chargement sera automatique à condition que chaque classe soit dans un fichier séparé NomDeLaClasse.php

    Faire un composant compatible composer c'est vraiment simple, lis la doc, rien à voir avec PEAR

  5. #5
    Membre très actif
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2011
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2011
    Messages : 154
    Par défaut
    Salut Benjamin,

    J'ai lu la doc que tu m'as passé, et je me suis lancé. J'ai installé composer puis via ce dernier Pimple, aucun problème à ce niveau... Ensuite, j'ai tenté un truc, et là je me fais des nœuds au cerveau.
    Citation Envoyé par Benjamin Delespierre Voir le message
    Le système tout-en-un est à l'opposé de l'approche orientée composant.
    Ma foi, le but c'est pas le tout en un, mais disons que je voulais faire un système de require avec pimple pour certains fichiers. D'ailleurs un truc dans le style de l'injecteur de dépendances que tu présentes sur ton site:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $app->addModel('articles', function () use ($app) {
        include_once $app['models_path'] . '/articles.php';
        return new Articles($app['article']);
    });
    Citation Envoyé par Benjamin Delespierre Voir le message
    BTW, l'autoload c'est vraiment vraiment simple
    Je connais l'autoload, mais je préfère ne l'utiliser que pour les fichiers dont j'ai le moins besoin.
    Citation Envoyé par Benjamin Delespierre Voir le message
    Faire un composant compatible composer c'est vraiment simple, lis la doc, rien à voir avec PEAR
    Oui, j'ai jeté un œil, vite fait, et c'est vrai que ça a l'air pas trop compliqué. Pour l'instant j'en ai plus l'utilité pour importer des trucs, mais je ferai mes composants dans quelques temps...

    J'ai quelques problèmes avec pimple, je posterai mon code tout à l'heure.
    @+

  6. #6
    Expert confirmé
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Par défaut
    Je connais l'autoload, mais je préfère ne l'utiliser que pour les fichiers dont j'ai le moins besoin.
    Il n'y a pas de réelle différences de perfs entre l'usage d'un autoloader et l'inclusion classique: http://blog.ircmaxell.com/2012/07/is...-solution.html

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $app->addModel('articles', function () use ($app) {
        include_once $app['models_path'] . '/articles.php';
        return new Articles($app['article']);
    });
    Ce bout de code était là pour illustrer qu'on pouvait déterminer au runtime le composand modèle à charger sans pour autant rentrer dans le détail de ce qu'il faut vraiment faire en réalité: utiliser les namespaces et laisser l'autoloader se démerder. Comme le but de l'article c'était pas d'expliquer les namespaces et que ça aurait pris trop de temps d'aller jusqu'au bout (j'essaie de ménager mes lecteurs) j'ai utilisé une just-in-time inclusion, ce qui n'est pas franchement beau. Je vais peut être changer ça...

    Donc Pimple n'a pas besoin de charger les composants, il n'est d'ailleurs qu'un conteneur qui sert à faire de l'injection de dépendances, en réalité c'est pas lui qui fait l'injection

    Dans une architecture propre, c'est l'autoloader qui s'occupe de tout.

  7. #7
    Membre très actif
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2011
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2011
    Messages : 154
    Par défaut chargeur de foos
    Donc voilà, je veux faire un système de chargement automatique de foos.
    Le foo à charger dépend (par défaut) d'une variable super globale.
    index.php (le départ):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    //todo delete
    error_reporting(E_ALL);
    ini_set('display_errors','1');
     
    require 'core/tools/FooCtx.php';
    $ctx=new \Core\FooCtx();
    $foo=$ctx['GET_FOO']();
    FooCtx (le chargeur de foo à proprement parler, mais il aura également d'autres attribution par la suite)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <?php
    namespace Core;
    require 'Context.php';
     
    class FooCtx extends Context{
     
        public function __construct() {
            parent::__construct();
            $this['FOO_PATH']='foo/';
            $ctx=$this;
            $this['GET_FOO']=function($fooName=NULL) use ($ctx){
                var_dump($fooName);
                if(empty($fooName))
                        $fooName=  end($ctx['URI']);
                $ctx['REQUIRE']($ctx['FOO_PATH'].$fooName.'.php');
                return new $fooName($ctx);
            };
        }
    }
     
    ?>
    Puis Context, qui est un chargeur plus générique, et qui aura également d'autres attributions ensuite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?php
    namespace Core;
    require 'vendor/pimple/pimple/lib/Pimple.php';
     
    class Context extends \Pimple{
     
        public function __construct() {
            $this['REQUIRED_CLASS_FILES']=array();
            $ctx=$this;
            $this['REQUIRE']=function($file) use ($ctx){
                //var_dump($file);
                if(!array_key_exists($file, $ctx['REQUIRED_CLASS_FILES'])){
                    require $file;
                    $ctx['REQUIRED_CLASS_FILES'][$file]=TRUE;
                }
            };
            //Storing URI parameters
            $uri=array();
            $i=1;
            while (!empty($_SERVER['REDIRECT_arg'.$i]))
                    $uri[]=$_SERVER['REDIRECT_arg'.$i++];
            $this['URI']=$uri;
        }
    }
     
    ?>
    Mon foo de test se contente pour l'instant de faire un echo hello world.
    Mon problème se situe au niveau de la classe FooCtx, pour GET_FOO:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $this['GET_FOO']=function($fooName=NULL) use ($ctx){
                var_dump($fooName);
    J’appelle la closure dans index.php de cette manière:
    Je m'attendais donc à ce que $fooName soit NULL. Or, il n'en est rien $fooName est une instance de FooCtx, ce que je ne m'explique pas. Serait-ce du à Pimple? Je cherche pour l'instant dans le code de pimple pour essayer de comprendre. Mais j'ai peut-être fait quelque chose d'une mauvaise manière. Aurait-tu une idée?

    Problème n°2: De quel manière (juste les grandes lignes), tu mettrais en place des tests unitaires pour tester ce code? J'avoue que je sais pas trop par où commencer.
    Merci,
    @+
    Piero

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [EJB3] [JBoss] Injection de dépendance circulaire ?
    Par Claythest dans le forum Java EE
    Réponses: 6
    Dernier message: 04/08/2009, 08h11
  2. [EJB3] Injection de dépendance et Stateful
    Par newbeewan dans le forum Java EE
    Réponses: 1
    Dernier message: 15/05/2007, 07h33
  3. [Integration] [EasyMock] Injection de dépendance à l'éxécution
    Par frangin2003 dans le forum Spring
    Réponses: 2
    Dernier message: 06/03/2007, 11h06
  4. Spring + TagSupport et injection de dépendance
    Par worldchampion57 dans le forum Spring Web
    Réponses: 2
    Dernier message: 26/02/2007, 09h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo