我有服务层类来执行业务逻辑。
我有一个班级UserService
,它执行与用户角色相关的服务,例如检查用户是否为管理员,用户是否有权访问项目,用户是否具有特定角色等。还有另一个班级说{{ 1}}处理项目相关的事情,如获取项目成员,项目详细信息等。
ProjectService
我正在使用Slim 3,我使用它的UserService
$projectService; //class variable
hasProjectAccess(){
{
...
projectMember = projectService->getProjectMembers();
...
}
isUserAdmin(){
return true|false; //just an example
}
ProjectService
$userService; //class variable
getProjectMembers(){
{
...
perform some logic to create array of members
...
if(userService.isUserAdmin())
.. perform some other logic
...
}
类来实例化并注入所有依赖项。
现在,当我尝试实例化Container
类时,我必须在其中实例化UserService
类(使用setters方法),而后者必须实例化UserService类....等等。 ..创建一个无限循环(循环依赖)。
我正在尝试实现像Java / Spring这样的东西,你在类中需要不同的服务,并且使用Spring连接到它,所以你不必担心循环依赖。
除了基础知识,我对PHP并不熟悉。
如果需要更多信息,请与我们联系。
答案 0 :(得分:0)
Pimple并不像Java中的Spring那样强大。它只是一个简单的容器,只具有基本功能。
因此,当只使用疙瘩函数时,您需要自己初始化具有循环依赖性的对象:
class A {
private $b;
public function __construct(B $b) { $this->b = $b; }
}
class B {
private $a;
public function setA(A $a) { $this->a = $a; }
}
$container = new \Slim\Container;
$b = new B;
$a = new A($b);
$b->setA($a);
$container['A'] = function($c) use ($a) {
return $a;
};
$container['B'] = function($c) use ($b) {
return $b;
};
$aFromContainer = $container['A'];
我对苗条容器进行了一些小改动,可以自动化这个过程(通过这项工作,我不知道它在大型项目中的表现如何)。
class MyContainer extends \Slim\Container
implements \Interop\Container\ContainerInterface {
private $resolveStack = [];
private $resolveLater = [];
/**
* @see \Pimple\Container::offsetSet()
*
* Additionally define objects which will be later set with a method.
*/
public function resolveLater(string $id, callable $value, array $later) {
$this[$id] = $value;
foreach($later as $item) {
if(!isset($this->resolveLater[$item])) $this->resolveLater[$item] = [];
$this->resolveLater[$item][] = $id;
}
}
/**
* @see \Pimple\Container::offsetGet()
*
* Additionally set objects which were previously defined in #resolveLater.
*/
public function offsetGet($id) {
if(isset($this->resolveStack[$id])) { return $this->resolveStack[$id]; }
$this->resolveStack[$id] = parent::offsetGet($id);
if(isset($this->resolveLater[$id])) {
foreach($this->resolveLater[$id] as $item) {
$this[$item]->{'set' . $id}($this->resolveStack[$id]);
}
}
return array_pop($this->resolveStack);
}
}
上述示例:
class A {
public function setB(B $b) { $this->b = $b; }
public function setC(C $c) { $this->c = $c; }
}
class B {
public function setA(A $a) { $this->a = $a; }
public function setC(C $c) { $this->c = $c; }
}
class C {
public function setA(A $a) { $this->a = $a; }
public function setB(B $b) { $this->b = $b; }
}
$container = new MyContainer;
$container->resolveLater('A', function($container) {
return new A;
}, ['B', 'C']);
$container->resolveLater('B', function($container) {
return new B;
}, ['A', 'C']);
$container->resolveLater('C', function($container) {
return new C;
}, ['A','B']);
$a = $container['C'];
var_dump($a);
这将输出如下内容:
object(C)[20]
public 'b' =>
object(B)[22]
public 'a' =>
object(A)[21]
public 'b' =>
&object(B)[22]
public 'c' =>
&object(C)[20]
public 'c' =>
&object(C)[20]
public 'a' =>
object(A)[21]
public 'b' =>
object(B)[22]
public 'a' =>
&object(A)[21]
public 'c' =>
&object(C)[20]
public 'c' =>
&object(C)[20]