【问题标题】:How do I make my PHP IDE understand Dependency Injection Containers?如何让我的 PHP IDE 理解依赖注入容器?
【发布时间】:2011-09-17 18:04:27
【问题描述】:

当前情况:我的项目中有依赖项,我使用依赖注入解决了这些依赖项。我想通过使用依赖注入容器 (DIC) 来简化我的依赖管理和延迟加载类,从而采取下一个逻辑步骤。

我查看了Bucket、Pimple 和sfServiceContainer,进行了一些测试,非常欣赏 DIC 的工作方式。我可能会选择 Pimple,因为它的简单性和原始力量。如果我没有这个问题:

由于 DIC 提供的抽象,我使用的 IDE (PHPStorm) 不再理解我的代码中发生了什么。它不理解 $container['mailer'] 或 $sc->mailer 持有一个类对象。我也试过 Netbeans IDE:同样的问题。

这对我来说确实是个问题,因为我的 IDE 变得毫无用处。在处理类时,我不想在没有代码提示、自动完成和重构工具的情况下进行编程。而且我不希望我的 IDE 在验证代码时发现各种误报。

所以我的问题是:有没有人处理过这个问题并找到了解决方案?

【问题讨论】:

  • 你可以尝试通过phpdocumentor标签/** @var $inst My_Object **/ $inst = $sc->mailer;
  • 如果您有兴趣在 PHPStorm 中获得支持,可以对 WI-17116 投票。

标签: php ide dependency-injection phpstorm


【解决方案1】:

您可以“手动”定义变量的类:

/** @var YourClassType $mailer */
$mailer = $container['mailer'];

在 PhpStorm(和 standards)中,使用两个星号并将数据类型写在变量名称之前。

可以不写变量名的数据类型(但不能写不带数据类型的名字)。

【讨论】:

  • 您发布的链接是关于类变量的。
  • @hakre:它也适用于普通变量;)
  • @nikic:你怎么看这个标题:@var - 记录类变量的数据类型?可以很好地匹配 PHPDoc 的范围,但无论如何,不​​需要迂腐。
  • netbeans 不支持此示例(认为应该),但确实从 phpdoc 标签中获取类型。
  • 我认为诀窍是你想在容器中定义一次,而不是每次使用它 - 用 phpdoc 乱扔代码。
【解决方案2】:

虽然您可以在每次访问时告诉您的 IDE 从容器中提取的对象的类型,最好只执行一次。以下两种解决方案都涉及对容器进行子类化。我刚开始使用 Pimple,建议还是这样做。

对于使用通过-> 访问或通过魔术__get 方法公开的实例成员的容器,您可以告诉您的IDE 它们持有什么类型。这很棒,因为它在代码运行时不涉及任何额外的解析——只有 IDE 会被它打扰。

/**
 * My container. It contains things. Duh.
 *
 * @property MyService $service
 * @property MyDao $dao
 */
class MyContainer extends Container { }

对于 Pimple 和其他充当数组的容器,您可以为所需的顶级对象创建访问器函数。虽然这意味着在创建容器时需要进行更多的解析,但它应该只完成一次并保存在 APC 中。无论如何,我非常喜欢一种方法而不是数组访问,因为它将容易忘记的数组键放在自动完成的方法中。

class MyContainer extends Pimple
{
    /**
     * @return MyService
     */
    public function getMyService() {
        return $this['service'];
    }
}

顺便说一句,对于 NetBeans 中带有 @var 的类型提示内联变量,您需要使用带有 一个星号的 /*。这不是文档块注释,不适用于/** 或//。此外,名称位于类型之前。

public function foo() {
    /* @var $service MyService */
    $service = $container['service'];
    ...
}

【讨论】:

  • +1 表示有关单个星号的提示。双星号为我打破了它。谢谢。
  • 单个星号语法也适用于 Eclipse PDT,谢谢!
  • 在 PhpStorm 中,双星号有效。 /** @var MyService $service */.
  • 对于@property docblock.. 这可以与magic __get() 结合使用。但它也适用于数组访问吗?我对此表示怀疑。 (至少在 PhpStorm 中)
  • @donquixote 不,@property 仅用于通过-> 访问财产。对于数组访问,您需要创建访问器函数,直到为 PHPDoc 创建新注释并由 IDE 实现。
【解决方案3】:

由于 IDE 不执行代码,他们不知道并需要您的帮助。我知道这也适用于 Eclipse 和其他 IDE:提示变量的类型。

Netbeans / Phpstorm / PDT / ZendStudio 示例

/* @var $mailer MailerInterface */
$mailer = $sc->mailer

代码完成在$mailer 上再次开始工作。

对于 PDT,重要的是:

  1. 评论仅以* 开头。
  2. 首先是变量名,然后是提示。

替代注释变体

因为它受到了很多讨论,它在 IDE 之间可能会有所不同。但是,大多数 IDE 都以上述方式支持内联代码变量的变量提示。因此,根据 IDE 的不同,这可能会以不同的方式编写,但类似,例如前面有两个星号:

/** @var $mailer MailerInterface */

PHPDoc 兼容性

如果你模仿类 var doc-comment 的内联代码,PHPDoc 解析器可能会出现问题:

/** @var MailerInterface $mailer  */

该文档通常用于类变量 (@var - Document the data type of a class variable)。 PHPDoc 在注释之后缺少类变量的定义,这对 QA 来说是一个负担。

但是,当使用 PHPDoc 类变量样式编写时,一些 IDE 也会为简单变量提供代码补全。我不知道这是否对当前类的代码完成有副作用,然后可能会引入一个实际上不存在的新成员。

【讨论】:

  • 请添加另一个星号以使其成为有效的 phpdoc 注释。
  • 第二个例子显示了错误使用 phpdoc-comment。类型只能是 BEFORE 变量。它仅用于支持旧代码。 manual.phpdoc.org/HTMLframesConverter/default/phpDocumentor/…
  • @nikic:我不敢这样做,因为这是函数体代码而不是 phpdoc 注释。
  • @hakre 所以 PDT 是个废话。因为 phpdoc 的标准告诉首先编写数据类型(请参阅前面评论中的链接)。
  • @OZ_:请原谅,但您似乎误读了您链接的关于类变量的 phpdoc 规范。这不是类变量,而是函数体中的代码。根据您链接的规范,PDT 自然支持类变量的 PHPDoc cmets。
【解决方案4】:

对于那些从谷歌来到这里的人。

PHPStorm 实际上提供了一种解决此类问题的方法,而不是一遍又一遍地编写 PHPDocs — 创建和设置 .phpstorm.meta.php 文件以 described here 获得顺利工作的自动完成和类型检查。

【讨论】:

    【解决方案5】:

    Pimple 只是介绍容器构建器的原理。如果你明白了,你就不再需要疙瘩了:

    
    class Container
    {
        private $shared = array();
    
        public function getService() {
            return new Service(
                this->getFirstDependence(),
                this->getSecondDependence()
            );
        }
    
        protected function getFirstDependence() {
            return new FirstDependence(
                this->getSecondDependence()
            );
        }
    
        protected function getSecondDependence() {
            return isset($this->shared[__METHOD__]) ? $this->shared[__METHOD__] : $this->shared[__METHOD__] =
            new SecondDependence(
            );
        }
    }
    

    这样 Pimple 不会在混合 $c['some key'] 中隐藏对象类型。编辑容器时,您将获得自动完成建议。 Phpstorm 能够从您的代码中自动解析方法返回类型。你会有透明的容器。您可以覆盖容器:

    
    class TestContainer extends Container
    {
        protected function getFirstDependence() {
            return new FirstDependenceMock(
            );
        }
    }
    

    说实话,用“编程”语言编写的容器是错误的方法。容器的职责是将对象的初始化图带给调用者。访问“编程语言”可以轻松违反该责任。一些用于配置依赖的 DSL 更好。此外,大多数原始依赖信息(构造函数的参数类型提示)只是被 Pimple 和 sfDepenencyContainer 忽略,使您的配置变得臃肿和脆弱。

    【讨论】:

    • 这种方法的唯一问题是它不是面向对象的 - 它只使用类...在您的示例中,Container 不可重用,因为您需要向它添加/删除方法每次你有一个新的依赖。使用 Pimple,您只需注册新的依赖项,并且永远不会像您一样更改类的内部结构(类应该禁止修改)。
    • 只是为了确保人们不会考虑到这一点,我强烈建议不要这样做。基本上我在这里所做的是创建一个具有预配置依赖链的服务提供者。不可维护。
    【解决方案6】:

    我知道这个问题只是关于 DIC,但是有一个 Silex Pimple Dumper 服务提供者将容器转储到一个 json 文件中。同一作者写了一个plugin for PHPStorm,它可以读取该文件并使用服务名称及其类型(类、字符串等)打开自动完成功能。我正在使用这两个组件,我可以说这是 Silex/Pimple 自动完成的不错选择。

    【讨论】:

    • 这正是我正在寻找的。这改变了一切。 :D
    猜你喜欢
    • 2014-09-15
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-30
    相关资源
    最近更新 更多