tags:

views:

1945

answers:

3

I have a class for interacting with a memcache server. I have different functions for inserting, deleting and retrieving data. Originally each function made a call to memcache_connect(), however that was unnecessary, eg.

mc->insert()
mc->get()
mc->delete()

would make three memcache connections. I worked around this by creating a construct for the class;

function __construct() {
    $this->mem = memcache_connect( ... );
}

and then using $this->mem wherever the resource was needed, so each of the three functions use the same memcache_connect resource.

This is alright, however if I call the class inside other classes, eg;

class abc
{
    function __construct() {
        $this->mc = new cache_class;
    }
}    
class def
{
    function __construct() {
        $this->mc = new cache_class;
    }
}

then it is still making two memcache_connect calls, when it only needs one.

I can do this with globals but I would prefer not to use them if I don't have to.

Example globals implementation:

$resource = memcache_connect( ... );

class cache_class
{
    function insert() {
     global $resource;
     memcache_set( $resource , ... );
    }
    function get() {
     global $resource;
     return memcache_get( $resource , ... );
    }

}

Then no matter how many times the class is called there will only be one call to memcache_connect.

Is there a way to do this or should I just use globals?

+4  A: 

Pass in the MC instance:

class abc
{
    function __construct($mc) {
        $this->mc = $mc;
    }
}    
class def
{
    function __construct($mc) {
        $this->mc = $mc;
    }
}

$mc = new cache_class;
$abc = new abc($mc);

etc.

Greg
+7  A: 

I would code another class using singleton pattern for getting the only instance of memcache. Like this -

class MemCache 
{ 
  private static $instance = false;   
  private function __construct() {}

  public static function getInstance()
  { 
    if(self::$instance === false)
    { 
      self::$instance = memcache_connect(); 
    } 

    return self::$instance; 
  } 
}

and usage -

$mc = MemCache::getInstance();
memcache_get($mc, ...)
...
Matajon
It's a reasonable solution but let's face it, it's a global. :)
cletus
This is what I'd do. You can't test it, but let's be honest, who tests this kind of thing anyway?
Philip Morton
The question is how testable stays the rest of the whole code if one small part isn't testable.Or how would you implement a simulated MemCache object for other tests?
okoman
@cletus: It's using a global pattern, but it's not using the global scope. Programs run in an environment; at that level of organization, everything's a global, even if you've got all your real data inside class properties.You want to avoid having *variables* in global, but interfaces to external data sources have to live somewhere, and you want Singleton for those anyway.
dirtside
+1  A: 

I think you're looking for static properties here.

class mc {
    private static $instance;

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

    private function __construct() {
        $this->mem = memcache_connect(...);
    }
}

This implements a basic singleton pattern. Instead of constructing the object call mc::getInstance(). Have a look at singletons.

Ross
Funny how people down vote after having read no more than the first sentence of an answer. +1 again.
Tomalak