访问DI容器 [英] Accessing the DI container
问题描述
我正在开始一个新项目,并建立工作基础.出现了一些问题,我可能会在这里问很多,希望我能找到一些答案.
第一步是处理对象的依赖关系.我已经决定采用依赖注入设计模式(这是我的新手)来为应用程序处理所有这些操作.
在实际编码时,我遇到了一个问题.如果一个类具有多个依赖关系,并且您想通过构造函数传递多个依赖关系(这样,在实例化对象后就不能更改它们).
如何使用call_user_func_array(),eval()或Reflection不传递依赖项数组来做到这一点?这就是我正在寻找的东西:
<?php
class DI
{
public function getClass($classname)
{
if(!$this->pool[$classname]) {
# Load dependencies
$deps = $this->loadDependencies($classname);
# Here is where the magic should happen
$instance = new $classname($dep1, $dep2, $dep3);
# Add to pool
$this->pool[$classname] = $instance;
return $instance;
} else {
return $this->pool[$classname];
}
}
}
同样,我想避免使用最昂贵的方法来调用类.还有其他建议吗?
此外,如何在类内部访问DI类,例如,在需要访问不同模型的控制器中?我应该静态地调用它还是将其传递给需要它的每个类?我认为最后一个想法不可行.
谢谢大家.
[在我开始之前,我要说我主要是Java程序员,只有一点点PHP知识.但是,我只会尝试在没有语言细节的情况下获得最重要的概念.]
依赖注入基于代码的两个部分:
- 建筑
- 执行
在其最极端的形状中,在执行部分中找不到new
运算符.所有这些都移入了建筑"部分. (实际上,这将被减弱.)
所有构造都发生-在构造部分.它会创建自下而上执行所需的对象图.因此,让我们假设,它应该构造A:
- A取决于B,并且
- B取决于C.
然后
- 首先构建C.
- 然后用C作为参数构造B.
- 然后用B作为参数构造A.
因此,不必将C作为构造函数参数传递给A.这个小例子并不能说明太多,这多少减少了必须传递的对象数量./p>
不应该将依赖项注入器本身传递到执行部分.这是每个人(包括我自己)初次接触DI时都会犯的基本错误之一.问题在于,这将完全模糊构造与执行之间的界线.换句话说,这将违反《得墨meter耳法律》 .或用模式来说:最终将依赖注入"模式降级"到服务定位器模式.如果这确实是降级的话,这是有争议的,但是在任何情况下,将依赖注入器用作服务定位器通常不是一个好主意.
因此,每当需要在执行过程中向其中一个构造的对象提供生成其他对象的能力时,只需传递简单的提供程序(Java DI框架
比方说,B取决于C. 提供程序是构造代码的一部分,因此您可以使用 I'm starting a new project and setting up the base to work on. A few questions have risen and I'll probably be asking quite a few in here, hopefully I'll find some answers. First step is to handle dependencies for objects. I've decided to go with the dependency injection design pattern, to which I'm somewhat new, to handle all of this for the application. When actually coding it I came across a problem. If a class has multiple dependencies and you want to pass on multiple dependencies via the constructor (so that they cannot be changed after you instantiate the object). How do you do it without passing an array of dependencies, using call_user_func_array(), eval() or Reflection? This is what i'm looking for: Again, I would like to avoid the most costly methods to call the class. Any other suggestions? Also, how do I access the DI class inside classes, for example, in controllers that need to access different models? Should I call it statically or pass it along each class that would require it? I don't think the last idea is feasible. Thanks everyone. [Before I start, let me say that I'm mostly a Java programmer - with only a little bit of PHP knowledge. But I'll simply try to get the most important concepts across without language specifics.] Dependency Injection is based on two parts of code: In its most extreme shape, there are no All of the construction happens - in the Construction part. It creates the graph of objects needed for Execution bottom up. So let's assume, it should construct A: Then So C doesn't have to be passed as a constructor parameter to A. This small example doesn't illustrate strongly enough, how much this reduces the amount of objects that have to be passed around to quite a small number. The Dependency Injector itself should not be passed into the Execution part. This is one of the basic mistakes everyone (including myself) tries to make, when they first come in contact with DI. The problem is, that this would completely blur the lines between Construction and Execution. Another way to say it is, that it would violate the Law of Demeter. Or in pattern speak: It would eventually "degrade" the Dependency Injection pattern to the Service Locator pattern. It's debatable, if this is really a degradation, but in any case it's usually not a good idea to misuse the Dependency Injector as a Service Locator. So whenever you need to give one of your constructed objects the capability to produce other objects during execution, instead of passing the Dependency Injector, you would only pass simple Providers (a term used by the Java DI framework Guice). These are rather simple classes that can only create a certain kind of object. They have similarities with a factory. First try to pass the required dependencies directly to the constructor. So, to sum it up: But don't take it too far: Simple objects can still be created without a Provider :-) And now, all you'll have to do is to translate this stuff into quality code. Maybe others can help you out with a few PHP examples. Addendum: A little bit more about Providers As noted above, the notion "Provider" (a specialized factory) is a bit specific to the Java DI framework Guice. This framework can automatically create a Provider for any type of object. However, the concept is generally useful for DI. The only difference is, that without the help of Guice or a similar framework, you'll have to write the Providers yourself - but that's quite easy: Let's say, B depends on C. Providers are part of the Construction code, so you're allowed to use 这篇关于访问DI容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
get()
方法编写一个名为CProvider
的类,该类可以创建C的新实例.然后将CProvider
的实例传递给C B的构造函数,并将Provider存储在B的实例字段中.现在B在需要新的C实例时可以调用cProvider.get()
.new C(...)
!另一方面,它们不属于执行代码,因此您不应在其中执行任何逻辑.CProvider
当然可以传递给多个构造函数.您还可以编写多个版本CProvider1
,CProvider2
,...-其中每个版本都可以构造具有不同属性的C对象的不同版本.或者,您可以使用不同的参数多次简单地实例化CProvider
.<?php
class DI
{
public function getClass($classname)
{
if(!$this->pool[$classname]) {
# Load dependencies
$deps = $this->loadDependencies($classname);
# Here is where the magic should happen
$instance = new $classname($dep1, $dep2, $dep3);
# Add to pool
$this->pool[$classname] = $instance;
return $instance;
} else {
return $this->pool[$classname];
}
}
}
new
operators to be found in the Execution part. All of them are moved into the Construction part. (In practice, this will be toned down.)
CProvider
with a get()
method, that can create a new instance of C. Then pass an instance of CProvider
into the constructor of B, and store the Provider in an instance field of B. Now B can call cProvider.get()
when it needs a new instance of C.new C(...)
! On the other hand, they're not part of the Execution code, so you shouldn't have any execution logic there.CProvider
can be passed into multiple constructors of course. You can also write multiple versions CProvider1
, CProvider2
, ... - where each can construct different versions of C objects with different properties. Or you simple instantiate CProvider
multiple times with different arguments.