2

How do inject array of implementations into class through constructor. I am sharing the link which is c#. I want to achieve the same in php.

How to achieve same in php.

public interface IFoo { }
public class FooA : IFoo {}
public class FooB : IFoo {}

public class Bar
{
    //array injected will contain [ FooA, FooB ] 
    public Bar(IFoo[] foos) { }
}

public class MyModule : NinjectModule
{
    public override void Load()
    {
        Bind<IFoo>().To<FooA>();
        Bind<IFoo>().To<FooB>();
        //etc..
    }
}

https://stackoverflow.com/a/13383476/1844634

Thanks in advance.

user1844634
  • 1,221
  • 2
  • 17
  • 35

2 Answers2

1

PHP does not support generics duo to run-time performance difficulty. So there are no way to explain that you expect all interfaces via definition of contractor. So you have to configure DI container manually. To explicitly tell that your class needs all classes that support some kind of interface.

Laravel for configuration use ServiceProvider to do all kind of configuration: In the class \App\Providers\AppServiceProvider you can configure creation of your class.


    public function register(): void
    {
        // to configure implementation for an interface or abstract class
        // you can only configure one implementation for interface
        $this->app->bind(\App\IFoo::class, \App\FooA::class);

        // or 'tag' several implementation for one string tag.
        $this->app->tag([\App\FooA::class, \App\FooB::class], \App\IFoo::class);

        $this->app->bind(\App\Bar::class, function(\Illuminate\Contracts\Foundation\Application $container){
            // get all tagged implementations
            $foos = $container->tagged(\App\IFoo::class);

            return new \App\Bar($foos);
        });
    }

112Legion
  • 1,129
  • 12
  • 25
0

You may need to use Tagging. For example, perhaps you are building a report aggregator that receives an array of many different Report interface implementations. After registering the Report implementations, you can assign them a tag using the tag method:

$this->app->bind('App\Reports\MemoryReportInterface', 'App\Reports\MemoryReportImplementation');       
$this->app->bind('App\Reports\SpeedReportInterface', 'App\Reports\SpeedReportImplementation');  

$this->app->tag(['App\Reports\MemoryReportInterface', 'App\Reports\MemoryReportInterface'], 'reports'); 

Once the services have been tagged, you may easily resolve them all via the tagged method:

$this->app->bind('ReportAggregator', function ($app) {
    return new ReportAggregator($app->tagged('reports'));
});

Usage

<?php 

namespace ...;

/**
 * 
 */
class ReportAggregator
{
    private $reports;

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

    public function getReports() {
        return $this->reports;
    }
    //...
}
Foued MOUSSI
  • 4,643
  • 3
  • 19
  • 39
  • I want my class to depend on abstractions.Rather than the concrete implementations. How i can achieve here? – user1844634 Feb 03 '20 at 14:34
  • If i am not wrong it should be same interface. Same interface implemented by two concrete classes. It should be either of MemoryReportInterface or SpeedReportInterface – user1844634 Feb 03 '20 at 14:48
  • please look the example at that i mentioned in the question and update the answer please. Thanks in advance. – user1844634 Feb 03 '20 at 14:52