PHP Classes

File: CachedArray.class.php

Recommend this page to a friend!
  Classes of Ingvar Stepanyan   Cached Virtual Array   CachedArray.class.php   Download  
File: CachedArray.class.php
Role: Class source
Content type: text/plain
Description: Class file
Class: Cached Virtual Array
Base class for implementing persistent arrays
Author: By
Last change: - Speed increased
- Some fixes to code (now can work after flush, better iterator)
- Better readability of code
- Now only getItem, setItem, addItem are abstract; other methods use them by default but can be overridden
- Countable is no more part of the class
Date: 13 years ago
Size: 5,602 bytes
 

Contents

Class file image Download
<?php
// Name: CachedArray.class.php
// Author: RReverser
// Description: Cached virtual array for PHP
// Version: 1.1
// Created: 27.03.2011

class CachedArrayIterator implements Iterator
{
    private
$indexArray, $cachedArray;
   
    function
__construct(CachedArray $ca)
    {
       
$this->cachedArray = $ca;
       
$this->indexArray = $ca->items();
    }
   
    function
current() { return $this->valid() ? $this->cachedArray[$this->key()] : NULL; }
    function
key() { return current($this->indexArray); }
    function
next() { next($this->indexArray); return $this->current(); }
    function
rewind() { reset($this->indexArray); return $this->current(); }
    function
valid() { return key($this->indexArray) !== NULL; }
}

// Cached array class - implements full array-style or object-style access to elements

abstract class CachedArray implements ArrayAccess, Serializable, IteratorAggregate
{
    const
sDELETED = -2, sEXISTS = -1, sUNCHANGED = 0, sMODIFIED = 1, sNEW = 2;

    protected
$cache = array(), $addCount = 0, $listed = FALSE, $autoFlush = TRUE;

   
// Your functions (for overriding)
   
abstract function getItem($index);
    abstract function
setItem($index, $value);
    abstract function
addItem($value = NULL);
    function
delItem($index) { $this->setItem($index, NULL); }
    function
hasItem($index) { return $this[$index] !== NULL; }
    function
getList() { return array(); }

    function
__construct($autoFlush = TRUE) { $this->autoFlush = $autoFlush; }
    function
__destruct() { $this->autoFlush ? $this->flush() : FALSE; }

   
// Functions for object-style access
   
function __get($index) { return $this[$index]; }
    function
__set($index, $value) { $this[$index] = $value; }
    function
__isset($index) { return isset($this[$index]); }
    function
__unset($index) { unset($this[$index]); }

   
// Functions for array-style access
   
function offsetGet($index)
    {
        if (!isset(
$this->cache[$index]) || $this->cache[$index][0] == self::sEXISTS)
        {
           
$this->cache[$index] = array(self::sUNCHANGED, $this->getItem($index));
        }

        return
$this->cache[$index][0] >= 0 ? $this->cache[$index][1] : NULL;
    }

    function
offsetSet($index, $value)
    {
        if (
$index === NULL)
        {
           
$index = 'new_' . $this->addCount++;
           
$State = self::sNEW;
        } else
        {
           
$State = isset($this[$index]) ? self::sMODIFIED : self::sNEW;
        }

       
$this->cache[$index] = array($State, $value);
    }

    function
offsetExists($index)
    {
        if (isset(
$this->cache[$index]) && $this->cache[$index][0] != self::sDELETED)
        {
            return isset(
$this->cache[$index][1]);
        } else
        {
           
$exists = $this->hasItem($index);
           
$this->cache[$index] = array($exists ? self::sEXISTS : self::sUNCHANGED, NULL);
            return
$exists;
        }
    }

    function
offsetUnset($index)
    {
       
$this->cache[$index][0] = self::sDELETED;
    }

   
// Functions for serialization
   
function serialize() { return serialize(array($this->cache, $this->addCount, $this->listed, $this->autoFlush)); }
    function
unserialize($str) { list($this->cache, $this->addCount, $this->listed, $this->autoFlush) = unserialize($str); }

   
// Returning iterator object
   
function getIterator() { return new CachedArrayIterator($this); }

   
// Flushing procedure
   
function flush()
    {
       
$movements = array();

        foreach (
$this->cache as $index => &$data)
        {
            switch (
$data[0])
            {
                case
self::sDELETED:
                   
$this->delItem($index);
                   
$data = array(self::sUNCHANGED, NULL);
                    break;
               
                case
self::sMODIFIED:
                   
$this->setItem($index, $data[1]);
                   
$data[0] = self::sUNCHANGED;
                    break;
               
                case
self::sNEW:
                   
$newIndex = $this->addItem($data[1]);
                   
$movements[$index] = $newIndex;
                    break;
            }
        }

        foreach (
$movements as $from => $to)
        {
           
$this->cache[$to] = array(self::sUNCHANGED, $this->cache[$from][1]);
            unset(
$this->cache[$from]);
        }

       
$this->addCount = 0;
    }

    function
drop()
    {
       
$this->cache = array();
       
$this->addCount = 0;
       
$this->listed = FALSE;
    }

   
// Listing of real and unflushed items
   
function items()
    {
        if (!
$this->listed)
        {
           
$result = $this->getList();

            foreach (
$result as $innerIndex => $index)
            {
                if (!isset(
$this->cache[$index])) { $this->cache[$index] = array(self::sEXISTS, NULL); }
                elseif (
$this->cache[$index][0] == self::sDELETED) { unset($result[$innerIndex]); }
            }
           
            foreach (
$this->cache as $index => $data)
            {
                if (
$data[0] == self::sNEW) { $result[] = $index; }
            }

           
$this->listed = TRUE;
        }
        else
        {
           
$result = array();
           
            foreach (
$this->cache as $index => $data)
            {
                if (
$data[0] >= self::sEXISTS) { $result[] = $index; }
            }
        }
       
        return
$result;
    }

}