PHP中的注册表或单例模式?

Registry or Singleton pattern in PHP?

我现在正在处理PHP类和对象。在这个问题中,字段和方法的名称是由它们组成的,这样您就可以了解我在说什么了。

它与使用单例和注册表设计模式有关。

现在假设我需要访问一个数据库对象、缓存对象、核心设置对象、会话对象,在我需要访问的几乎所有其他类中。所以我将使用一个注册表将所有4个对象存储到1个注册表类对象中。然后我可以轻松地将我的1个对象传递到任何其他需要访问这些对象的对象中。到目前为止这听起来不错,但是如果我有一些类不需要所有4个这些对象,如果我只需要访问数据库对象或者我的其他一些类中的会话对象呢?对于Perfromance,最好只在这些其他对象中使用一个单例,还是继续在这些对象中使用我的注册表?

我不太清楚这些对象在PHP中的工作方式,不知道是否会有任何形式的性能提升(内存使用率、CPU使用率、加载时间较短)。

因此,任何有这方面经验的人都可以告诉我,使用其中一个或另一个是否会有任何收获,我正处在一个阶段,我可以在不影响生产时间或任何事情的情况下走上另一条路。如果可以的话,我想用最好的方法。


您可以实现延迟加载以仅加载真正需要的对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Registry
{
    private static $database = null;

    private static function connectDatabase($key)
    {
        [... do connection stuff ...]
    }

    public static function getDatabase($key)
    {
        if (Registry::$database == null)
        {
            Registry::connectDatabase($key);
        }
        return Registry::$database;
    }
}

注册数据库连接参数的代码留给读者作为练习。


这取决于你的申请。如果您仍然需要四个类中的三个,那么使用注册表比单独处理三个类更理想,因为您不需要第四个类。延迟加载类是减少内存占用的一种方法,但是您需要指示注册表何时创建对象,这与处理单例没有太大的不同。或者,您可以创建一个n参数的构造函数,或者使用一个数组来指示注册表在构造期间实例化哪些类。

1
2
3
4
5
6
7
8
9
10
11
class Registry {
    public $class1;
    public $class2;

    function __construct($uses) {
        foreach($uses as $class) {
            $this->{$class} = new {$class}();
        }
    }

}

然后通过指定要实例化的类来实例化注册表。

1
$reg = new Registry(array('class1'));

显然,您希望构造函数处理零个参数,以说明默认情况下实例化所有类。


也许这是正确的单例注册模式。OFC,您可以实现不同的东西,splFixedArray、arrayaccess接口和其他。此外,添加析构函数并销毁内部对象也不错,以确保不会发生泄漏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class oRegistry{
   private static $instance = null;

   private $storage = array();

   private function __construct(){}

   private function __clone(){}

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

   public function attach($name, $o) {
      if( true === isset($this->storage[$name]) ) {
          throw new Exception('The instance with name '.$name.' already exists in registry.');
      }
      if( !empty( $name ) ) {
          $this->storage[ $name ] = $o;
      }
   }

   public function detach( $name ){
       if( isset( $this->storage[ $name ] ) ) {
           $this->storage[ $name ] = null;
           unset( $this->storage[ $name ] );
       }
   }

   public function get( $name ){
       if( false === isset( $this->storage[$name] ) ) {
           throw new Exception('Invalid instance requested');
       }
       return $this->storage[ $name ];
   }
}

// usage example
$storage = oRegistry::getInstance();
$obj = new stdClass;
$obj2 = new stdClass;
$obj->test1 = 'test';
$obj2->test2 = 't2';

$storage->attach( 'test1', $obj );
$storage->attach( 'test2', $obj2 );

$got = $storage->get( 'test2' );
var_dump($got); // object(stdClass)#3 (1) { ["test2"]=> string(2)"t2" }

$storage->detach( 'test2' );
$got = $storage->get( 'test2' );
var_dump($got); // bool(false)