0

I installed the memcache (without the D) extension for PHP. This is the function i'm using to create the memcache object just once, and then reuse it.

# Memcache handler
class mem {
    var $id;
    var $expire;
    public static $mem;

    # Constructor
    function __construct($unique) {
        # ID
        $this->id = md5($unique);

        # Item expiration
        $this->expire = 86400;

        # Create or reuse object
        if(!isset(self::$mem)) {
            # Create new connection
            self::$mem = new Memcache;
            self::$mem->addServer('localhost', 11211);
        }
    }

    # Get
    public static function get() {
        # Check if object is cached
        if($data = self::$mem->get($this->id)) {
            # ID is cached
            return $data;
        } else {
            # ID is not cached
            return false;
        }
    }

    # Set
    public static function set($id, $data, $replace=false) {
        if(self::$mem->add($this->id, $data, MEMCACHE_COMPRESSED, $this->expire)) {
            # Write to memory
            return true;
        } elseif($replace) {
            # Replace information
            self::$mem->replace($this->id, $merge, MEMCACHE_COMPRESSED, $this->expire);
            return true;
        } else {
            # Return nothing
            return false;
        }
    }

    # Delete key
    public static function delete() {
        if(self::$mem->delete($this->id)) {
            return true;
        } else {
            return false;
        }
    }
}

Usage examples

User writes data to memory:

mem::set('some_clever_ID', array('this','and','that'));

User grabs the data from memory:

$data = mem::get('some_clever_ID');

User prints the grabbed data:

print_r($data); //should print an array with ['this', 'and', 'that']

User deletes the key from memory:

mem::delete('some_clever_ID');

I have 2 questions:

  1. Why am I getting this error? Fatal error: Call to a member function add() on a non-object in /inc/memcache.php

  2. I wonder if there would be any way to improve the performance of this code, or if I should implement a different approach. The idea is to have a quick to manage memcache values and to reuse the memcache connection when possible.

Any help and comments will be highly appreciated.

Update: Solution

I ended up placing the memcache function outside of the class.

# Memcache settings
$config['memcache']['servers'][] = array('localhost',11211);
$config['memcache']['debug'] = true;

# Create memcached object
function cache() {
    global $config;
    static $cache;
    if(!isset($cache)) {
        $cache = new Memcache;
        foreach($config['memcache']['servers'] as $server) {
            $cache->addServer($server[0], $server[1]);
        }
    }
    return $cache;
}

# Memcache handler
class mem {
    var $id;
    var $expire;

    # Constructor
    function __construct($unique) {
        global $config;

        # ID
        $this->id = md5(PRO_NAME.'_'.$unique);

        # Item expiration
        if($config['memcache']['debug']) {
            $this->expire = 5;
        } else {
            $this->expire = 86400;
        }
    }

    # Get
    function get() {
        # Check if object is cached
        if($data = cache()->get($this->id)) {
            # ID is cached
            return $data;
        } else {
            # ID is not cached
            return false;
        }
    }

    # Set
    function set($data, $replace=false) {
        if(cache()->add($this->id, $data, MEMCACHE_COMPRESSED, $this->expire)) {
            # Write to memory
            return true;
        } elseif($replace) {
            # Replace information
            if(cache()->replace($this->id, $data, MEMCACHE_COMPRESSED, $this->expire)) {
                return true;
            } else {
                return false;
            }
        } else {
            # Return nothing
            return false;
        }
    }

    # Delete key
    function delete() {
        if(cache()->delete($this->id)) {
            return true;
        } else {
            return false;
        }
    }
}

Write example

$obj = new mem('clever_ID_here');
$obj->set('some data');
//or use $obj->set('some data', true); if you want to replace previous value

Grab example

$obj = new mem('clever_ID_here');
echo $obj->get();

Delete example

$obj = new mem('clever_ID_here');
$obj->delete(); //if you wish to delete the key
Andres SK
  • 10,779
  • 25
  • 90
  • 152

2 Answers2

3

$mem is a static property on your class so instead of accessing it as $mem

you should use self::$mem;

From a class design standpoint you should not be using global in the constructor for the class , you should instead pass a reference of the config object into the class. For example:

 function __construct($unique, $config) {

Since all of the methods are being called statically there is a good chance the constructor is never being called.

To get arround this you can create a protected static method to serve you up with an instance of the memcached

protected static function getMemcache() {

    # Create or reuse object
    if(!isset(self::$mem)) {
        # Create new connection
        self::$mem = new Memcache();
        self::$mem->addServer('localhost', 11211);
    }
    return self::$mem;
}

Everywhere you currently access self::$mem replace it with self::getMemcache()

Orangepill
  • 24,500
  • 3
  • 42
  • 63
  • it is weird, i changed all $mem calls to self::$mem but im still getting the "Fatal error: Call to a member function add() on a non-object" error (first example). – Andres SK Jun 10 '13 at 17:23
  • 1
    you also need to assign it as a static property `$mem = new Memcache;` should be `self::$mem = new Memcache;` – Orangepill Jun 10 '13 at 17:30
  • I already did that. Maybe it has something to do with the $mem variable scope? – Andres SK Jun 10 '13 at 17:31
  • Everywhere in your code that has `$mem` should be changed to `self::$mem` – Orangepill Jun 10 '13 at 17:33
  • I already replaced everything as well. The "Call to a member function add() on a non-object" is still being displayed. – Andres SK Jun 10 '13 at 17:36
  • do you think it has something to do with the public static $mem; ? – Andres SK Jun 10 '13 at 17:50
  • print_r on the value of `self::$mem` – Orangepill Jun 10 '13 at 18:43
  • Strict Standards: Non-static method mem::get() should not be called statically in /inc/memcache.php --- Fatal error: Access to undeclared static property: mem::$mem in /inc/memcache.php – Andres SK Jun 10 '13 at 18:47
  • based on your usage example `function get() ` should be `public static function get()` – Orangepill Jun 10 '13 at 18:55
  • sorry for that, i forgot to add it when updating the code here. if i do use the `public static function` the print_r returns only this: Fatal error: Call to a member function get() on a non-object – Andres SK Jun 10 '13 at 18:58
  • i believe the __construct method is not being executed when i call the methods as an instance (e.g.: mem::get('something');) – Andres SK Jun 10 '13 at 18:58
  • then that's where i'm stuck hehe, any ideas why? or should i just create an instance to the object as this: `$users = new mem(); $users->get('something');` – Andres SK Jun 10 '13 at 19:00
  • still got into scope issues. I ended up placing the memcache function outside of the cache handler class. I just posted the alternative solution. – Andres SK Jun 10 '13 at 19:41
3

In the functions of your class, you have to do $this->mem instead of $mem.

I suggest you checking this class: PHPFastCache, which is very simple and allows you to use not only Memcache(d), but another caching systems as well, without changing anything in your code.

Marcelo Pascual
  • 810
  • 8
  • 20
  • thanks for the tip. ill try the PHPFastCache, still i would like to know why im still getting the error. I can't use $this because it is not in object context. – Andres SK Jun 10 '13 at 17:22