<?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;
}
}
|