Factory dependency injection

I am really new to DI, but I really want to try using it.

There is something I don’t understand. Here is a simple factory pseudo code, I use a lot.

class PageFactory {
   public function __construct(/* dependency list */) {
      ... //save reference to the dependencies
   }

   public function createPage($pagename) {
       switch ($pagename) {
           case HomePage::name:
               return new HomePage(/* dependency list */);
           case ContactPage::name:
               return new ContactPage(/* dependency list */);
           ...
           default:
               return null;
       }
   }
}

It has very simple logic, it selects a string-based implementation instance. This is very useful, because I can choose in the future which page I need, and only the one that will be created.

How can I rewrite this code, so the page instances will be created by the dependency container, so I won’t need to handle the dependencies for the factory and the pages it creates?

The only solution I see is to make the container that I want to use, a dependency for the factory, and make calls from it from the factory. I have a lot of problems with this.

-, factory .

-, , , (.. $container- > get ('Foo');). . , .

EDIT:

DI. . . DI factory, .

2:

Dice DI, , . , . - - , , DI .

3:

, . , , .

- , MVC- . MVC, , , . , .

. , . , , , , . . , , . DI.

, , , .

+4
4

: - , DI - , , ... , - buzz-

DI " factory". , , . , DI .

:

, Foo, Alpha Beta, . . Beta PDO DSN Cache.

DI .

, , DI.

Auryn.

+3

, . , : DI , , ? , -, ( )? , , ? , ... - , " DI", , SO:) ( DI)

, , , PHP. , Guice ( Java- Google, DI):

- "" ( "" ) , . . . , AngularJS - JS Google, - "" " " "..." : , " " , , " " DIC .

, -, ( ).

:

IMO, , DI, " " , , callin. , , , root. .

, PHP-DI DIC. , .

// 1. First, define interfaces of trivial factories that'll be used to
// create new objects using injector.
interface HomePageTrivialFactoryInterface {
    public function __construct(
        DI\Container $container
        // Injector is needed to fetch instance directly from it.
        // List of other dependencies that are already known at design
        // time also goes here.
    );
    public function __invoke(
        // List of dependencies that are computed only in runtime goes here
        // You may name this method something else, "create" for example,
        // but then you'll also have to specify this method name when
        // you'll wire things together in container definitions on step #3.
    ): HomePage;
}
// ContactPageTrivialFactoryInterface is defined similarly

// 2. Now in PageFactory::createPage we'll use the injected trivial
// factories to create page objects.
class PageFactory {
    private $homePageTrivialFactory;
    private $contactPageTrivialFactory;

    public function __construct(
        HomePageTrivialFactoryInterface $homePageTrivialFactory,
        ContactPageTrivialFactoryInterface $contactPageTrivialFactory
        // list of other dependencies that are already known at design time
        // also goes here
    ) {
        // save reference to the dependencies
    }

    public function createPage(
        $pagename
        // list of other dependencies that are computed only at runtime goes
        // here
    ) {
        switch ($pagename) {
            case HomePage::name:
                return ($this->homePageTrivialFactory)(
                    // Write here all the dependencies needed to create new
                    // HomePage (they're listed in
                    // HomePageTrivialFactoryInterface::get definition).
                    // Here you may use both the dependencies obtained from
                    // PageFactory::__construct (known at design time) and
                    // from PageFactory::createPage methods (obtained at
                    // runtime).
                );
            case ContactPage::name:
                return ($this->contactPageTrivialFactory)(
                    /* dependency list, similarly to HomePage */
                );
            // ...
            default:
                return null;
        }
    }
}

// 3. Now, let set up the injection definitions in the composition root.
// Here we'll also implement our TrivialFactoryInterface-s.
$containerDefinitions = [
    HomePageTrivialFactoryInterface::class => DI\factory(
        function (DI\Container $container): HomePageTrivialFactoryInterface
        {
            return new class($container)
                implements HomePageTrivialFactoryInterface
            {
                private $container;

                public function __construct(
                    DI\Container $container
                    // list of other design time dependencies
                ) {
                    // save reference to the dependencies
                }

                public function __invoke(
                    // list of run time dependencies
                ): HomePage
                {
                    return $this->container->make(HomePage::class, [
                        // list of all dependencies needed to create
                        // HomePage goes here in the following form.
                        // You may omit any dependency and injector will
                        // inject it automatically (if it can).
                        // 'constructor parameter name of dependency' =>
                        //     $constuctor_parameter_value_of_dependency,
                        // etc - list here all needed dependencies
                    ]);
                }
            };
        }
    ),
    // ContactPageTrivialFactoryInterface is defined similarly
];

// 4. Finally, let create injector, PageFactory instance and a page using
// PageFactory::createPage method.
$container = (new DI\ContainerBuilder)
    ->addDefinitions($containerDefinitions)
    ->build();
$pageFactory = $container->get(PageFactory::class);
$pageFactory->createPage($pageName);

, DI, , , inon anonimous classes ( PHP 7). , , , . . , 1, 2 4 : # 1 , , 2 4 , , PageFactory, . , , - 3- , :

// 3. Now, let set up the injection definitions in the composition root.
// Here we'll also implement our TrivialFactory-s and wire them to
// PageFactory constuctor parameters.
$containerDefinitions = [
    PageFactory::class => DI\object()
        ->constructorParameter('homePageTrivialFactory', DI\factory(
            function (
                DI\Container $container
                // list of other dependencies that are already known at
                // design time also goes here
            ) {
                function (
                    // list of run time dependencies
                ) use($container): HomePage
                {
                    return $container->make(HomePage::class, [
                        // list of all dependencies needed to create
                        // HomePage goes here in the following form:
                        // 'constructor parameter name of dependency' =>
                        //     $_constuctor_parameter_value_of_dependency,
                        // etc - list here all needed dependencies
                    ]);
                }
            }
        ))
        // ContactPageTrivialFactory is wired and defined similarly
    ,
];

, , , ( , , ), , . HomePage ( ), , , , . IMO , : , .

, @SinistraD, ?

+1

DI , , . , bad_boy .

DI

DI . , , , . , ( ), .

DI , . , , ​​ , DI .

, :

$router = $di->create(Router::class);
$pageClassName = $router->getRequestedPageClassName();
$page = $di->create($pageClassName);
echo $page->render();

, DI , , , , .

::

. , PHP 5.5. , PHP, PHP, ClassName:: class ClassName, , IDE, PHP. :: PHP 5.3, PHP, .php.

0

, DI DIC, .

class Router {

   private $loader;
   private $routes

   function __construct($container){
      $this->loader = $container->get('loader');
   }
}

, . , . .

, IDE - , docblocks

/**
* @property LoaderInterface $loader
*/ 

, factory?

class NotificationFactory {

   /**
    * @property ContainerInterface $container
    */
   private $container;

   function __construct($container){
     $this->container = $container;
   }

   public function create($user, $message){
     return new Notification(array(
        "to" => $user->email,
        "subject" => $message
     ), 
     $container);
   }
}

, Notification :

class Notification {

    /**
    * @property ContainerInterface $container
    */
    private $container;
    /**
    * @property TranslatorInterface $translator
    */
    private $translator;

    function __construct($container){
       $this->container = $container;
       $this->translator = this->container->get('translator');
    }

    function createMessage($message, $lang){
       return $translator->translate($message, $lang);
    }
}

, , .

, , , .

:

class FooController {
  function __construct($container, $request, $route){
     /** stuff happening here **/
  }

  function showAction($id) {
    return new Response(/** stuff happening here **/);
  }
}

-, /.

Symfony2, , , Fabian Potenciers ?

0
source

All Articles