拥有一个保存全局数据的容器类是个好主意吗


is it a good idea to have container class that keeps global data?

我正试图找到一种将所有php应用程序数据保存在一个地方的方法。例如,获取并发布参数、页面标题、分页结果等,以避免使用全局变量。

将所有数据和控制器之间的交换保存在以下对象中是个好主意吗?

class container {
protected static $_instance;
protected $_instance_class;
public static function instance($instance_name = 'default')
{
    $c = __CLASS__;
    if ( ! isset($c::$_instance[$instance_name]))
    {
        $c::$_instance[$instance_name] = new $c();
        $c::$_instance[$instance_name]->_instance_class = $instance_name;
    }
    return $c::$_instance[$instance_name];
}
public function set($key, $val)
{
    // someting like $this->$key = $val;
}
public function get($key)
{
    // someting like retrun $this->$key;
}
}

然后,例如在模型中

container::instance('messages')->set('error', 'some error');

并且在控制器或视图中

container::instance('messages')->get('error');

或者有其他方法可以让应用程序中的任何地方都可以访问数据吗?

谢谢!

您所谈论的是注册表模式(以及另一篇关于它的好文章)。虽然它有一些缺点(例如,为了测试从注册表中获取一些数据的方法,我们还必须模拟这个注册表),但它肯定比使用全局变量或Singleton要好。

事实上,在Zend Framework 1中,这个模式是完全按照字面意思实现的:

// setting a value (usually done in Bootstrap)
Zend_Registry::set('index', $value);
// getting a value (usually in actions and/or models)
$value = Zend_Registry::get('index');

为了展示这种方法可能存在的问题,让我们分析以下内容:

class FooController extends Zend_Controller_Action {
    public function barAction() {
        $baz = Zend_Registry::get('baz');
        $model = new Some_Model($baz); 
        ...
    }
}

问题很简单:这里的$baz是什么?它是一个物体吗?还是数组?或者其他野兽,比如功能或资源?你必须依赖这里的注释,这通常不是一件好事——除非你处理的是琐碎而常见的对象(比如查询参数或数据库资源对象)。

对于这种性质的东西,对静态类进行硬编码引用的问题在于,您正在创建对这些静态类的紧密依赖。如果您决定在将来更改"全局"属性的源,那么您的应用程序中就会充斥着对该源的引用。

如果你想要一个有点全局性的属性实体,一个更好的方法是创建一些你将实例化的东西,并提供一个适合你的应用程序需要的接口。为了便于讨论,让我们调用这个接口GlobalConfigurationProvider。然后,您的应用程序代码可能期望(并依赖)GlobalConfigurationProvider的一些实现。现在,如果您将来更改实现配置的方式,您只需要担心新元素——GlobalConfigurationProvider的新实例,而不必担心引用配置提供程序的所有类、视图等。

不要使用全局容器类,而是考虑编程OO,并将方法和变量放在一个类中。

在您的错误示例中,错误属于一个类,应该保留在那里。

对类的引用可以由全局注册表保存,或者更好的是,由IoC容器保存。