$expire) { break; } } $this[self::IDX_LOCK] = 1; } /** * Release the lock * * @return void */ private function unlock() { $this[self::IDX_LOCK] = null; } /** * Get the value of a key * * @param string $key * @return mixed */ public function get(string $key) { $map = (array)$this[self::IDX_MAP]; // If the key doesn't exist, return null if (!array_key_exists($key, $map)) { return null; } $index = $map[$key]; $keyvar = $this[self::IDX_DATA + $index]; // If for some reason we don't get anything back, return null if (!$keyvar) { return null; } // Save the checksum for later and return the value $this->checks[$key] = $keyvar[0]; return $keyvar[1]; } /** * Set a key to a specific value * * @param string $key * @param mixed $value * @param boolean $check * @return boolean */ public function set(string $key, $value, $check=false):bool { // Acquire a lock and fetch the map $this->lock(); $map = (array)$this[self::IDX_MAP]; // If the key doesn't exist in the map, we need to set it up if (!array_key_exists($key, $map)) { $free = 0; // Find first free index foreach ($map as $map_key=>$index) { if ($index != $free) { break; } $free++; } // Store the index in the map, and sort it by index. $map[$key] = $free; asort($map); $this[self::IDX_MAP] = $map; } // Look up the key and fetch the data $index = $map[$key]; $keyvar = $this[self::IDX_DATA + $index]; // Check the data to make sure the data hasn't changed since last read if ($check && $keyvar && array_key_exists($key, $this->checks)) { if ($keyvar[0] != $this->checks[$key]) { $this->unlock(); return false; } } // Update the data $this[self::IDX_DATA + $index] = [ md5($value), $value ]; $this->checks[$key] = md5($value); $this->unlock(); return true; } /** * Check if the map contains the key. This method doesn't acquire a lock * * @param string $key * @return bool */ public function contains(string $key):bool { $map = (array)$this[self::IDX_MAP]; return array_key_exists($key, $map); } }