65

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

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

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

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

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

4

6 回答 6

59

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

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

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

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

于 2011-06-18T11:59:53.153 回答
46

虽然您可以在每次访问时告诉您的 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您需要使用/*一个星号。这不是文档块注释,不适用于/**or //。此外,名称位于类型之前。

public function foo() {
    /* @var $service MyService */
    $service = $container['service'];
    ...
}
于 2011-06-20T22:38:12.470 回答
14

由于 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 - 记录类变量的数据类型)。PHPDoc 在注释之后缺少类变量的定义,这给 QA 带来了负担。

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

于 2011-06-18T11:46:37.863 回答
9

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

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

于 2017-01-15T15:03:46.350 回答
1

疙瘩只是介绍容器构建器原理。如果你理解它,你就不再需要 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 忽略,使您的配置变得臃肿和脆弱。

于 2012-07-07T13:26:14.687 回答
1

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

于 2016-03-08T22:29:44.633 回答