Php 如何在保持服务层抽象的同时使用Yii组件?

Php 如何在保持服务层抽象的同时使用Yii组件?,php,yii,service-layer,Php,Yii,Service Layer,我喜欢并使用Yii框架,尤其是它的“组件”,它们是惰性实例化的,您可以在配置文件中交换它们。有点像依赖注入lite 我试图使代码的业务逻辑完全独立于框架,以防我想重新调整代码的用途,甚至改变框架 假设我的服务层中有一个名为AccountService的类,它实现了IAccountService,并且有一个单参数构造函数 interface IAccountService { function getUserById($id); } class AccountService implemen

我喜欢并使用Yii框架,尤其是它的“组件”,它们是惰性实例化的,您可以在配置文件中交换它们。有点像依赖注入lite

我试图使代码的业务逻辑完全独立于框架,以防我想重新调整代码的用途,甚至改变框架

假设我的服务层中有一个名为AccountService的类,它实现了IAccountService,并且有一个单参数构造函数

interface IAccountService
{
  function getUserById($id);
}

class AccountService implements IAccountService
{
  private $_userRepository;

  public function __construct(IUserRepository $userRepository) {
    $this->_userRepository = $userRepository;
  }

  public function getUserById($id) {
    return $this->_userRepository->getById($id);
  }
}
太好了。到目前为止,它完全没有框架。现在,我想将其公开为一个Yii组件,这样它就可以被延迟实例化,并且很容易被Yii控制器和其他Yii组件使用

但是Yii组件(实现iaapplicationcomponent)必须完全没有构造函数参数,而我的类需要一个

有什么想法吗

这是我得到的。我对他们中的任何一个都不太满意;它们看起来都很精致,我从它们身上闻到了一种独特的气味

选项1-编写:我创建了一个名为“AccountServiceComponent”的类,该类实现了Yii的IApplicationComponent。由于构造函数的原因,它无法扩展my AccountService类,但它可以将一个类实例化为私有成员并包装其所有方法,如下所示:

class AccountServiceComponent implements IApplicationComponent, IAccountservice
{
  private $_accountService;

  public __construct() {
    $this->_accountService = new AccountService(new UserRepository());
  }

  public getUserById($id) {
    return $this->_accountService->getUserById($id);
  }
}
缺点:我必须像这样包装每个方法,这很乏味,可能会导致“baklava代码”。特别是考虑到将有多个服务类,每个都有多个方法

选项2-mixin:(或行为或特征,或当今的任何称呼。)

Yii(在php5.4之前编写)以实现IBehavior的类的形式提供“行为”。我可以创建一个扩展服务的行为类,并将其附加到组件:

class AccountServicesBehavior extends AccountService implements IBehavior
{
  // Implement the few required methods here
}

class AccountServiceComponent implements IApplicationComponent
{
  public function __construct() {
    $accountService = new AccountService(new UserRepository());
    $this->attachBehavior($accountService);
}
class AccountService implements IAccountService
{
  public $userRepository;

  public function __construct(IUserRepository $userRepository = null) {
    $this->userRepository = $userRepository;
  }

  public function getUserById($id) {
    return $this->_userRepository->getById($id);
  }
}

class AccountServiceComponent extends AccountService implements IApplicationComponent
{
}
缺点:我的组件不再正式实现IAccountService。也似乎变得过度与分层

选项3-可选构造函数参数

我可以将服务类的构造函数参数设置为可选,然后将其扩展为组件:

class AccountServicesBehavior extends AccountService implements IBehavior
{
  // Implement the few required methods here
}

class AccountServiceComponent implements IApplicationComponent
{
  public function __construct() {
    $accountService = new AccountService(new UserRepository());
    $this->attachBehavior($accountService);
}
class AccountService implements IAccountService
{
  public $userRepository;

  public function __construct(IUserRepository $userRepository = null) {
    $this->userRepository = $userRepository;
  }

  public function getUserById($id) {
    return $this->_userRepository->getById($id);
  }
}

class AccountServiceComponent extends AccountService implements IApplicationComponent
{
}
Cons:可选构造函数参数意味着该类现在可以实例化,而无需提供它所需的一切


…那么,我还缺少其他选择吗?还是我必须选择一个对我干扰最小的参数?

选项3,但选择对象作为可选参数听起来最好:

public function __construct(IUserRepository $userRepository = new UserRepository()) {
    $this->userRepository = $userRepository;
}

我想不出比你建议的更好的了。。。但现在我确实很烦恼,因为现在可以在不提供所需一切的情况下实例化该类……进一步考虑这个问题,我认为这是Yii中的一个缺陷,我希望在2.0版中有所改变。在了解了其他一些框架是如何做到这一点之后,能够使用闭包实例化组件就很好了,这样就可以以您需要的任何方式实例化组件。。