In response to services depending on 'variable dependencies' not being super awesome.
I don't really see this being a huge issue.....so long as no-once accidentally 'shares' (a.k.a. makes a 'singleton') out of something that depends on something that is unique per process. i.e. in the code:
function backupFile(ResponseFactory $responseFactory) {
//
}
so long as the ResponseFactory isn't shared, it isn't a problem. The function is passed a fresh ResponseFactory each time. If the service we were calling needed to be an object, and we didn't want to create it each time then it wouldn't be a problem to separate the constant dependencies from the variable dependencies by having the constant ones set in the constructor, and the variable ones in the method call:
class Controller {
function __construct(DBConnection $dbConnection) {
$this->dbConnection = dbConnection;
}
function foo(ResponseFactory $responseFactory) {
//$data = get some data from $this->dbConnection.
$responseFactory->create($data);
}
}
I will look into making a dev mode in Auryn where if you do something like:
class Request {..}
class ResponseFactory {
function __construct(Request $request) {... }
}
$injector->share('ResponseFactory');
$injector->make('ResponseFactory');
//This should throw an error - as the dependency is not shared, but class that needs it is...
//which leads to surprises.
From Igor's article:
As you can see, scopes lead to a lot of complexity. This is a mess.
I haven't looked at the way Symfony does scopes, I tend to get a headache whenever I read that code. I will take Igor at his word when he says:
However, in addition to construction, the container is also responsible for managing state and context transitions. There is no clear separation between construction time and runtime, which leads to a lot of complexity.
Yeah.......no. That would be bad. The container/injector shouldn't be managing that. Context/scope management is really a separate concern from just dependency injection.
I don't think scopes/contexts should be that complicated....so long as you do them programaticlly rather than trying to do them through configuration.
So for the example of having a long running task that can process multiple requests then I would do something like the following, if I wanted to be absolutely sure that I had isolated the things that are dependent on a variable dependency.
<?php
//BackgroundJobService
$injector = bootstrapApplication();
do {
$request = readRequestFromGlobalVars();
$contextObjects = [];
$contextObjects['Request'] = $request;
$injector = createContext($injector, $contextObjects);
$callable = getNextThingToProcessThatNeedsRequest();
$injector->execute($callable);
}
class ContextObject {
/** The type name that this object should be used for */
public $name;
/** The instance of the object that should be used.
public $instance;
}
function createContext(Injector $injector, $contextObjects) {
$injector = clone $injector;
foreach ($contextObjects as $contextObject) {
$injector->alias($contextObject->name, get_class($contextObject->instance));
$injector->share($contextObject->instance);
}
return $injector;
}
But as I said, I think that would only be a problem if someone had accidentally shared something that was dependent on a variable dependency.