$GLOBALS和依赖注入的替代方案


Alternative to $GLOBALS and Dependency Injection?

我正在开发的一个项目使用第三方库。目前,我将这些对象存储在一个全局变量(例如$GLOBALS['_HTMLPurifier'])中。

我知道每个人都说"不要在面向对象的代码中使用$GLOBALS,使用依赖注入"。问题是,这些类中的大多数都是为了简化开发人员的操作。例如:

<?php
namespace Sarciszewski'MyProject'Security;
$GLOBALS['_HTMLPurifier'] = new 'HTMLPurifier(
    'HTMLPurifier_Config::createDefault()
);
class XSS
{
    /* blah */
    public static function clean($input, $context)
    {
        /* logic here */
            $input = $_GLOBALS['_HTMLPurifier']->purify($input);
        /* other things here depending on $context */
    }
}

这个想法是,任何使用这个项目的人都只需要这样做:

<?php
namespace 'Otherdev'HelloWorld;
use 'Sarciszewski'MyProject as MyP;
$x = isset($_GET['url']) ? $_GET['url'] : '';
echo "<input type='"text'" name='"url'" value='"".MyP'Security'XSS::clean($x, 'attribute')."'" />";

我不想强迫人们注入依赖关系。我宁愿保留这些对象的一个全局实例。单身人士在这里合适吗?或者还有其他的设计模式应该遵循吗?

(最坏的情况是:我只是说去死吧,这样做,因为它能完成任务。)

澄清一下:我不是在制作一个其他人可能在他们的框架中使用的库,我是在制作一种称为其他人的库的框架。

我想以"少写多做"的方式,明确地隐藏除单元测试作者之外的所有依赖项注入。用户不应该将对象传递给任何东西。

可用性比正确性更重要(这仍然很重要,但没有那么重要)。此外,我想尽量减少额外的第三方依赖关系。PHPUnit、HTMLPurifier和Twig都是我真正使用的。

我正在评估:

  • 辛格尔顿
  • 全局变量

我不会评估的:

  • 依赖项注入

欢迎第四种选择。

您误解了OOP的含义。

你花在代码上的大部分时间并没有花在编写上。花在代码库上的绝大多数时间都花在了维护上,使其正确工作。OOP、测试、编码风格等都是减少你维护它的时间,减少你需要做的大部分工作的工具

OOP并不是为了"简化"事物,相反,OOP通常比函数式编程更难阅读和理解。OOP的目的是允许轻松重构层,而不必影响应用程序的其余部分。

我们可以整天争论为什么全局变量不好。但归根结底,全球空间是一个巨大的漏洞来源。依赖注入是一个很好的替代方案。

对于您的特定示例,传递HTML净化库听起来是个好主意。如果明天你会发现一个更好的库,可以提供更好的功能或性能,那么你可以通过使用依赖注入相对容易地切换。

与其尝试自制一个好的DI解决方案,不如使用一个已经存在的库。

PHP DI真的很好,因为它可以让你简单地键入hint,任何你想注入到__construct方法中另一个类中的类,它都会被自动包含!

这似乎不是一个答案,但这个问题是基于观点的。就我个人而言,我认为使用全局变量是一个非常糟糕的主意,因为它令人困惑,并且可能会在代码中引入一些非常难以跟踪的错误。我会100%建议使用一个非常简单的DI来处理这种情况。

在您的情况下(使用PHP-DI),您可以执行以下操作:

class XSS
{
    /**
     * @Inject
     * @var HTMLPurifier
     */
    public static $purifier;
    public static function clean($input, $context)
    {
        /* logic here */
            $input = self::$purifier->purify($input);
        /* other things here depending on $context */
    }
}