简体   繁体   English

将超出范围的数据传递给服务容器

[英]Passing out of scope data to a service container

I wish to create a new instance of SomeService which must be injected with some data which is not known when defining the service in Pimple.我希望创建一个SomeService的新实例,该实例必须注入一些在 Pimple 中定义服务时未知的数据。 The following technically works, but surely cannot be the proper way to do so.以下在技术上有效,但肯定不是这样做的正确方法。 How should this be accomplished?这应该如何实现?

<?php
use Pimple\Container;

class SomeService
{
    private $theNewData;
    public function __construct(MyPdo $pdo, array $theNewData){
        $this->theNewData=$theNewData;
    }
    public function getJsonString():string{
        return json_encode($this->theNewData);
    }
}
class MyPdo{}

function getServiceSometimeInTheFuture(Container $container):SomeService {
    $someFutureData= ['a'=>1,'b'=>2,'c'=>3,];

    /*
    How do I inject this content into SomeService other than using Pimple as a temporary transport?
    */
    $container['temp']=$someFutureData;
    $newInstance=$container['someService'];
    unset($container['temp']);
    return $newInstance;
}

require '../vendor/autoload.php';

$container=new Container();

$container['myPdo'] = function ($c) {
    return new MyPdo();
};

$container['someService'] = $container->factory(function ($c) {
    return new SomeService($c['myPdo'], $c['temp']);
});

$service = getServiceSometimeInTheFuture($container);
echo($service->getJsonString());

How do I inject this content into SomeService other than using Pimple as a temporary transport?除了使用 Pimple 作为临时传输之外,如何将此内容注入 SomeService?

I think the root cause for this problem is that future data is actually data as its name suggests, and it is going to change multiple times over the time, so it should not be passed to the service at the time of service definition, but every time the consumer method in the service ( getJsonString here) needs that data.我觉得这个问题的根本原因是future data顾名思义就是数据,随着时间的推移会发生多次变化,所以不应该在服务定义的时候传递给服务,而是每次服务中的使用者方法(此处为getJsonString )需要该数据的时间。

... which is not known when defining the service ...在定义服务时不知道

The data is not known, but how about the source of the data?数据是未知的,但是数据的来源呢? Could you write a new service to act as data provider, so the original service can get required data when required in the future ?你能不能写一个新的服务来充当数据提供者,这样原来的服务可以在未来需要的时候获取需要的数据?

I can suggest two solutions.我可以提出两种解决方案。
(I intentionally removed MyPdo from everywhere because it was not used at all, even in the constructor) (我故意从任何地方删除 MyPdo 因为它根本没有使用,即使在构造函数中也是如此)

If you really need the data to be passed to the service at creation time:如果您确实需要在创建时将数据传递给服务:

<?php
require __DIR__ . '/../vendor/autoload.php';
use Pimple\Container;

class SomeService
{
    private $theNewData;
    public function __construct(array $theNewData){
        $this->theNewData=$theNewData;
    }
    public function getJsonString():string{
        return json_encode($this->theNewData);
    }
}

$container=new Container();

// Use pimple factory method to create new service instance, instead of creatng a custom function
$container['getServiceSometimeInTheFuture'] = $container->factory(function (Container $c):SomeService {
    return new SomeService($c['futureData']);
});

// `futureData` returns new data every time
$container['futureData'] = $container->factory(function(){
    return ['a' => rand(1, 10), 'b' => rand(1, 10), 'c' => rand(1, 10), ];
});

$service1 = $container['getServiceSometimeInTheFuture'];
$service2 = $container['getServiceSometimeInTheFuture'];

// Demonstrate how two different instances have different, persistent data
echo("\nservice 1:" . $service1->getJsonString());
echo("\nservice 2:" . $service2->getJsonString());
echo("\nservice 1:" . $service1->getJsonString());
echo("\nservice 2:" . $service2->getJsonString());

If you can postpone providing data to the service at the time it needs that data in the future:如果您可以推迟在将来需要该数据时向该服务提供数据:

<?php
require __DIR__ . '/../vendor/autoload.php';
use Pimple\Container;

// DataProvider decides what data should be provided to the service
class DataProvider {
    public function getData(){
        return ['a' => rand(1, 10), 'b' => rand(1, 10), 'c' => rand(1, 10), ];
    }
}

class SomeService
{
    private $dataProvider;
    public function __construct(DataProvider $dataProvider){
        $this->dataProvider=$dataProvider;
    }
    public function getJsonString():string{
        return json_encode($this->dataProvider->getData());
    }
}

$container=new Container();

// Use pimple factory method to create new service instance, instead of creatng a custom function
$container['getServiceSometimeInTheFuture'] = $container->factory(function (Container $c):SomeService {
    return new SomeService($c['dataProvider']);
});

$container['dataProvider'] = function() {
    return new DataProvider;
};

$service = $container['getServiceSometimeInTheFuture'];

// Demonstrate how THE SAME INSTANCE will have different data every time
echo("\n" . $service->getJsonString());
echo("\n" . $service->getJsonString());
echo("\n" . $service->getJsonString());
echo("\n" . $service->getJsonString());

Use Pimple's raw() method.使用 Pimple 的raw()方法。

$container->raw('someService')($container, $someFutureData);

The service will need to be set up to accept the new data.需要设置该服务以接受新数据。

$container['someService'] = $container->factory(function ($c, $data) {
    return new SomeService($c['myPdo'], $data);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM