【问题标题】:PHP Constructor and Dependencies ShorthandPHP 构造函数和依赖关系简写
【发布时间】:2013-06-06 05:37:39
【问题描述】:

如今,随着越来越多的面向服务的 PHP 被开发出来,我发现自己有很多 PHP 文件,其中有这么长的代码块只是为了初始化。在 C++ 或 typescript 等其他语言中,您可以执行以下操作而无需所有重复。一个 PHP 示例:

namespace Test\Controllers;
use Test\Services\AppleService;
use Test\Services\BananaService;
use Test\Services\PearService;
use Test\Services\LemonService;
use Test\Services\PeachService;

class TestController{

    protected $appleService;
    protected $bananaService;
    protected $lemonService;
    protected $pearService;
    protected $peachService;

    public function __construct(
    AppleService $appleService,
    BananaService $bananaService,
    LemonService $lemonService,
    PearService $pearService,
    PeachService $peachService
    ){
        $this->appleService = $appleService;
        $this->bananaService = $bananaService;
        $this->lemonService = $lemonService;
        $this->pearService = $pearService;
        $this->peachService = $peachService;
    }
}

打字稿示例:

module namespace Test.Controllers {
    export class TestController{
        constructor(
        private appleService:Test.Services.AppleService,
        private bananaService:Test.Services.BananaService,
        private lemonService:Test.Services.LemonService,
        private pearService:Test.Services.PearService,
        private peachService:Test.Services.PeachService
        ){}
    }
}

是否有更好/更短的方法来做同样的事情,和/或是否有任何支持可以使即将发布的 PHP 版本更容易地计划?

【问题讨论】:

  • 依赖注入容器,比如 Pimple?
  • @MarkBaker 处理未定义的实例化。另外,pimple 更像是一个服务定位器,然后是一个 DI 容器……虽然仍然有用。
  • 我认为您对此感到困惑。我可以提供的唯一缩写是您可以放弃 use 语句以支持使用命名空间类名,但我不认为这是一个有意义的改进。正如@MarkBaker 所说,DI 容器/服务定位器可以减轻创建和管理实例的痛苦。
  • 我知道依赖注入容器。但是,为了使我的代码更易于测试,我宁愿不注入整个容器。属性注入对我来说就像是黑客攻击。 PHP5.5+ 没有解决这个问题的计划吗?

标签: php dependency-injection soa


【解决方案1】:

还有一种替代方法,属性注入:

use DI\Annotation\Inject;

class TestController
{
    /**
     * @Inject
     * @var AppleService
     */
    private $appleService;
    /**
     * @Inject
     * @var BananaService
     */
    private $bananaService;
    /**
     * @Inject
     * @var LemonService
     */
    private $lemonService;
    /**
     * @Inject
     * @var PearService
     */
    private $pearService;
    /**
     * @Inject
     * @var PeachService
     */
    private $peachService;
}

是更短,还是更容易写?我让你判断。但我喜欢它,我最终不会得到一个臃肿的构造函数。这灵感来自 Java/Spring FYI。

现在这个例子适用于PHP-DI(免责声明:我正在研究那个),但可能还有其他提供相同功能的 DI 容器。

警告:属性注入并非无处不在。

我发现它适用于控制器(因为控制器不应该被重用)。 Read more here.

我认为在服务中使用它是不合适的。所以这不是最终的解决方案。

【讨论】:

    【解决方案2】:

    这种语法糖最终将在 PHP 8.0(2020 年 11 月 26 日)中出现。

    通过在构造函数中为参数添加前缀public、protected 或private,它们将被复制并定义为具有相同名称的类属性。

    在 PHP 8.0 中,OP 的例子可以写成:

    namespace Test\Controllers;
    
    use Test\Services\AppleService;
    use Test\Services\BananaService;
    use Test\Services\PearService;
    use Test\Services\LemonService;
    use Test\Services\PeachService;
    
    class TestController{
    
       public function __construct(
           protected AppleService $appleService,
           protected BananaService $bananaService,
           protected LemonService $lemonService,
           protected PearService $pearService,
           protected PeachService $peachService
       ){
       }
    }
    

    https://wiki.php.net/rfc/constructor_promotion

    https://stitcher.io/blog/constructor-promotion-in-php-8

    【讨论】:

      猜你喜欢
      • 2017-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-24
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多