让对象在 PHP 中随处可用的首选方法是什么?

What's the preferred way of having an object available everywhere in PHP?

我正在从事的项目要求我有一些对象,包括事件管理器、(只读)配置管理器和插件管理器,它们在系统中随处可用。

我一直在为这些使用全局变量,直到有人(具有 C++ 背景)友好地指出 "You're probably doing something wrong if you need global variables"。
他建议使用传递给所有需要它的函数的状态对象。
所以我做了:

$state = new State();
$state->register('eventManager' , new EventManager());
$state->register('configManager', new ConfigManager());
$state->register('cacheManager' , new CacheManager());
$state->register('pluginManager', new PluginManager());

$state->get('pluginManager')->initialize($state);

虽然我可以在更多有状态的语言中看到这种方法的好处,但在像 PHP 这样的(主要是?)无状态语言中,它对我来说似乎毫无意义,在页面打开后状态丢失加载完成。

在像 PHP 这样的(主要是)无状态语言中传递状态对象是否有任何好处,它是否比其他方法(即基于全局的系统)有任何好处,是否有更好的方法处理这个?

一种方法是使用 单例:

class ConfigManager {
    private static $instance = NULL;

    public static function getInstance(){
        if(self::$instance === NULL) {
            self::$instance = new ConfigManager();
        }

        return self::$instance;
    }

    private function __construct(){
         // Notice that this is private - only getInstance() can call this.
    }
}

// When you need it:
$config = ConfigManager::getInstance();

对于如何做你所要求的事情有很多不同的看法——而且我自己也不认为单例总是最好的方法。这真的取决于你的 use-case。

也就是说,单例只是 class 的一种常见模式,其实例应该随处可访问。

您建议的注册表仍然是一个全局变量。而如果你想访问一个全局变量(即使它是一个对象,尽管是一个全局变量),你就做错了。

一个合适的应用程序只在全局状态发挥作用的阶段:引导它时。启动脚本的请求是全局的,任何随它发送的请求数据都是全局的,任何影响应用程序并存储在文件或其他适当存储中的配置都是全局的。

第一阶段应该初始化一些依赖注入,将组成应用程序的所有部分放在一起。当请求的处理决定了应该调用代码的哪一部分来响应请求时,将按需创建该对象图。

通常这个决定是在处理请求的框架内完成的,依赖注入也可能通过框架完成。您自己的代码将只接受操作所需的值或所需的其他对象。

例如,如果您的代码需要一个数据库,那么您将配置数据库对象以接受您的数据库的 URL 和凭据,然后您将配置您的 reader对象接受该数据库对象。

依赖注入的任务是创建一个或多个数据库对象。您不必使用过时的 "singleton antipattern",因为它有很多缺点。

所以在这个场景中,依赖注入部分存在一些对象,只创建一次,在需要的时候注入。这些对象不强制只创建一次,并且它们不存储在可全局访问的变量中。然而,有些东西必须存在于全局变量中,但这只是主要的框架对象,也可能是依赖注入容器,它们永远不会作为全局变量共享到其余代码中——所以这根本没有害处。