Location: PHPKode > scripts > AppCache for PHP5 > Appcache For PHP5/Appcache For PHP5.php
<?php 
   
/** 
 * Application scope in PHP - implemented with Memcache. 
 *  
 * By Chris Dary of Arc90, Inc. 
 * hide@address.com 
 * http://www.arc90.com 
 * 
 * This work is licensed under a Creative Commons Attribution 3.0 License 
 * http://creativecommons.org/licenses/by/3.0/ 
 *  
 * Example code available at http://lab.arc90.com/ 
 * 
 **/ 
class Application 
{ 
    // private variables 
    private $key;            // The memcache key - the only required parameter. 
    private $cache;            // The array to temporarily store objects in after they are pulled from memcache. 
    private $memcache_keys;    // Associative array of objects that are currently available through memcache. Value is their expire timestamp, or false if never. 

    // memcached specific variables 
    private $memcached_obj; 
    private $memcached_prefix; 
    private $memcached_servers; 

    /** 
     * constructor __construct 
     * Constructor for the Application class. Sets up our configuration, and connects to the memcache daemon. 
     * @param array an associative array of initial values. 
     **/                    
    public function __construct( $configarray ) 
    { 
        // If configarray is just a string, that means that the 
        // user wants to use the defaults. Just set the key. 
        if(is_string($configarray)) 
        { 
            $this->key = $configarray; 
        } 
        else 
        { 
            // Parse our configuration options 
            foreach($configarray as $k=>$v) 
            { 
                switch($k) 
                { 
                    case 'key': 
                    case 'name': 
                        $this->key = $v; 
                        break; 
                    case 'memcached_servers': 
                        // If they passed in a string, make it a single element in an array. Otherwise, use the array they passed. 
                        $this->memcached_servers = is_array($v) ? $v : array($v); 
                        break; 
                    case 'memcached_prefix': 
                        $this->memcached_prefix = $v; 
                        break; 
                    default: 
                        throw new Exception('Unknown parameter "' . $k . '" passed with value "' . $v . '"'); 
                } 
            } 
        } 

        if(!$this->key) 
            throw new Exception("Application key is a required argument."); 
         
        // Set Defaults 
        if(class_exists("Memcache")) 
            $this->memcached_obj = new Memcache; 
        else 
            throw new Exception("You do not have the PHP extension for memcache installed."); 

        if(!$this->memcached_servers) 
            $this->memcached_servers = array("localhost:11211"); 

        if(!$this->memcached_prefix) 
            $this->memcached_prefix = "appvar_"; 
         
        // Sanitize the key (only alphanumerics and underscores), and add the prefix to avoid scoping issues with other memcache keys. 
        $this->key = $this->memcached_prefix . preg_replace("/[^a-zA-Z0-9_]/","",$this->key); 

        // Set up our connection 
        $connectSuccess = false; 
        foreach($this->memcached_servers as $server) 
        { 
            if(strpos($server,':')) 
            { 
                list($host,$port) = explode(':',$server); 
            } 
            else 
            { 
                $host = $server; 
                $port = 11211; 
            } 
            $connectSuccess |= $this->memcached_obj->addServer($host, $port); 
        } 

        if(!$connectSuccess) 
            die("Could not connect to a memcache daemon"); 

        // We're done configuring. Initialize our backend. 
        $this->prepare_cache(); 
    } 

    /** 
     * function prepare_cache 
     * prepare the object in the backend to store our data. If it doesn't exist, create it. 
     * @return bool true on success, false on failure 
     **/ 
    private function prepare_cache() 
    { 
        // Set up our caching array 
        $this->cache = array(); 

        $this->memcache_keys = $this->memcached_obj->get($this->key); 

        // Was our shared memory already initialized before? 
        if($this->memcache_keys) 
        { 
            // Yes, it was already created. Initialize our array of keys associated with this application. 
            if(!is_array($this->memcache_keys)) 
                $this->memcache_keys = unserialize($this->memcache_keys); 

            // Remove any expired keys 
            $mkeys = array_keys($this->memcache_keys); 
            $keys_modified = false; 
            foreach($mkeys as $k) 
            { 
                if($this->memcache_keys[$k] && $this->memcache_keys[$k] < time()) 
                { 
                    $keymod = true; 
                    unset($this->memcache_keys[$k]); 
                } 
            } 
            // If we removed any keys from expiration, we want to update that on memcached. 
            if( $keys_modified ) 
                $this->update_keys(); 

            return ($this->memcache_keys != false); 
        } 
        else 
        { 
            // No, it wasn't yet initialized. So initialize it. 
            return $this->create_memcache(); 
        } 
    } 

    /** 
     * function create_memcache 
     * Create a new object in the backend to store our data 
     * @return bool true on success, false on failure 
     **/ 
    private function create_memcache() 
    { 
        $this->memcache_keys = array(); 
        $this->memcached_obj->set($this->key,array()); 

        return true; 
    } 

    /** 
     * function clear 
     * Clears the application structure, as well as their references in the memcache backend 
     * Useful for flushing out all variables from the application. 
     * @return bool true on success, false on failure 
     **/ 
    public function clear() 
    { 
        foreach(array_keys($this->memcache_keys) as $k) 
            $this->memcached_obj->delete($k); 

        $this->cache = array(); 
        $this->memcache_keys = array(); 

        return $this->create_memcache(); 
    } 

    /** 
     * function __get 
     * Get a cached property. If it's in our local cache, return it. Otherwise, get it from memcache. 
     * @param string Name of property to return 
     * NOTICE: This uses some ArrayObject trickery to avoid passing array objects erroneously. 
     *         See http://derickrethans.nl/overloaded_properties_get.php 
     * @return mixed The requested value      
     **/ 
    public function __get( $name ) 
    { 
        if(!isset($this->cache[$name])) 
            $this->cache[$name] = $this->memcached_obj->get($this->keyify($name)); 

        return is_array($this->cache[$name]) ? new ArrayObject($this->cache[$name]) : $this->cache[$name]; 
    } 

    /** 
     * function __set 
     * Overrides __set to implement custom object properties. Updates our local variable, as well as in memcache. 
     * @param string Name of property to set 
     * @param mixed Value of property 
     * @return bool true on success, false on failure 
     **/ 
    public function __set( $name, $value ) 
    { 
        $key = $this->keyify($name); 
        $this->cache[$name] = $value; 

        if(!isset($this->memcache_keys[$key])) 
        { 
            $this->memcache_keys[$key] = false; 
            $this->update_keys(); 
        } 

        return $this->memcached_obj->set($key, $value); 
    } 

    /** 
     * function setWithExpire 
     * Same as __set, except it allows an expiration date to be set. 
     * Syntax: $app->setWithExpire('key', 'value', [expire]) where [expire] is  
     * @param string Name of property to set 
     * @param mixed Value of property 
     * @param integer Expiration time of the item. If it's equal to zero, the item will never expire. You can also use Unix 
     *                 timestamp or a number of seconds starting from current time, but in the latter case the number of seconds 
     *                 may not exceed 2592000 (30 days) or it will be parsed as a timestamp. 
     * @return bool true on success, false on failure 
     **/ 
    public function setWithExpire( $name, $value, $expire ) 
    { 
        if(is_string($expire)) 
            $expire = strtotime($expire); 

        $key = $this->keyify($name); 

        $this->cache[$name] = $value; 
        if(!isset($this->memcache_keys[$key])) 
        { 
            $this->memcache_keys[$key] = $expire < 2592000 ? (time()+$expire) : $expire; 
            $this->update_keys(); 
        } 


        return $this->memcached_obj->set($key, $value, 0, $expire);; 
    } 

    /** 
     * function __isset 
     * Overrides __isset to implement custom object properties. Checks if the object name was provided in our memcache_keys array. 
     * @param string Name of property to check 
     **/           
    public function __isset( $name ) 
    { 
        $k = $this->keyify($name); 

        if( isset($this->memcache_keys[$k])) 
        { 
            if( $this->memcache_keys[$k] !== false && $this->memcache_keys[$k] >= time() ) 
            { 
                // Our key has not yet expired, so cache it for this request and return it. 
                // This is done to avoid a race condition where the object expires between isset() and __get() 
                $obj = self::__get($name); 
                return ($obj !== false); 
            } 
            return true; 
        } 

        return false; 
    } 

    /** 
     * function __unset 
     * Overrides __unset to properly delete an item from memcache 
     * @param string Name of property to unset 
     **/           
    public function __unset( $name ) 
    { 
        unset($this->memcache_keys[$this->keyify($name)]); 
        unset($this->cache[$name]); 
        $this->memcached_obj->delete($this->keyify($name)); 
    } 

        /** 
         *  function getKeys 
         *  Get the list of keys for this application, without the key scoping. 
         *  @return array the keys, with values of expiration timestamp if it exists, or false if it does not. 
         **/ 
        public function getKeys() 
        { 
                $keylist = array(); 
                $find = $this->key . '_'; 
                foreach(array_keys($this->memcache_keys) as $k) 
                { 
                  $keylist[str_replace($find,'',$k)] = $this->memcache_keys[$k]; 
                } 
                return $keylist; 
        } 
     
    /** 
     * function update_keys 
     * Update the global keys object in memcache 
     **/ 
    private function update_keys() 
    { 
        return $this->memcached_obj->set($this->key, $this->memcache_keys); 
    } 

    /** 
     * function keyify 
     * Turn a variable name into its corresponding memcache key 
     * @param string Name of property to keyify 
     **/ 
    private function keyify( $name ) 
    { 
        return $this->key . '_' . $name; 
    } 

} 
?> 
Return current item: AppCache for PHP5