Created
July 9, 2024 01:15
-
-
Save mikeschinkel/2e7ac67d6948c2774b381599dfa339aa to your computer and use it in GitHub Desktop.
PHP Classes Statics\MemStream and Statics\MemCache (NOT memcached-related.)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
spl_autoload_register(function (string $class) { | |
if (preg_match("#^Statics\\\Mem(Cache|Stream)$#", $class)) { | |
$class = str_replace('\\', '/', $class); | |
include dirname(__DIR__) . "/{$class}.php"; | |
} | |
}); | |
\Statics\MemCache::runExample(); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Statics; | |
/** | |
* Class MemCache | |
* | |
* Handles static memory caching — NOT TO BE CONFUSED with `memcached`. | |
*/ | |
class MemCache { | |
/** | |
* Static property to hold items stored in memory and indexed by handle. | |
* | |
* @var array | |
*/ | |
private static array $mem = []; | |
/** | |
* Runs an example showing how to use static mem stream. | |
* | |
* @return void | |
*/ | |
public static function runExample(): void { | |
MemStream::init(); | |
$handle = MemCache::newHandle(); | |
$fp = fopen( MemCache::getStreamUrl( $handle ), "r+" ); | |
fwrite( $fp, "line1\n" ); | |
fwrite( $fp, "line2\n" ); | |
fwrite( $fp, "line3\n" ); | |
rewind( $fp ); | |
while ( ! feof( $fp ) ) { | |
echo fgets( $fp ); | |
} | |
fclose( $fp ); | |
var_dump( MemCache::getValue( $handle ) ); | |
MemCache::closeHandle( $handle ); | |
} | |
/** | |
* Generates a new unique handle (key) into the internal self::$mem array. | |
* | |
* @return int The unique handle. | |
*/ | |
public static function newHandle(): int { | |
do { | |
// Generate a random number between 1,000,000 and 9,999,999 | |
$handle = mt_rand( 1000000, 9999999 ); | |
} while ( array_key_exists( $handle, self::$mem ) ); // Ensure the handle is unique | |
// Add the handle to the memory array | |
self::$mem[ $handle ] = ''; | |
// Return the unique handle | |
return $handle; | |
} | |
/** | |
* Gets the URL to use with fopen(), Phar(), etc. | |
* | |
* @param int $handle The handle for which to get the URL. | |
* | |
* @return string The URL associated with the handle. | |
*/ | |
public static function getStreamUrl( int $handle ): string { | |
/** @noinspection PhpUnhandledExceptionInspection */ | |
self::checkHandle( $handle ); | |
return "staticmem://{$handle}"; | |
} | |
/** | |
* Sets the value stored by handle in static memory. | |
* | |
* @param int $handle The handle for which to set the value. | |
* @param string $value The value to be stored. | |
* | |
* @return void | |
*/ | |
public static function setValue( int $handle, string $value ): void { | |
/** @noinspection PhpUnhandledExceptionInspection */ | |
self::checkHandle( $handle ); | |
self::$mem[ $handle ] = $value; | |
} | |
/** | |
* Concatenates to a value stored by handle in static memory. | |
* | |
* @param int $handle The handle for which to concatenate the value. | |
* @param string $value The value to concatenate. | |
* | |
* @return void | |
*/ | |
public static function concatValue( int $handle, string $value ): void { | |
/** @noinspection PhpUnhandledExceptionInspection */ | |
self::checkHandle( $handle ); | |
self::$mem[ $handle ] .= $value; | |
} | |
/** | |
* Gets the value stored by handle in static memory. | |
* | |
* @param int $handle The handle for which to get the value. | |
* | |
* @return string|null The value stored or null if not found. | |
*/ | |
public static function getValue( int $handle ): ?string { | |
/** @noinspection PhpUnhandledExceptionInspection */ | |
self::checkHandle( $handle ); | |
return self::$mem[ $handle ]; | |
} | |
/** | |
* Gets a substring of the value stored by handle in static memory. | |
* | |
* @param int $handle The handle for which to get the substring. | |
* @param int $pos The start position of the substring. | |
* @param int $count The length of the substring. | |
* | |
* @return string|null The substring or null if not found. | |
*/ | |
public static function getSubstrValue( int $handle, int $pos, int $count ): ?string { | |
/** @noinspection PhpUnhandledExceptionInspection */ | |
self::checkHandle( $handle ); | |
return substr( self::$mem[ $handle ], $pos, $count ); | |
} | |
/** | |
* Gets the string length of the value stored for the handle in static memory. | |
* | |
* @param int $handle The handle for which to get the string length. | |
* | |
* @return int The length of the stored value. | |
*/ | |
public static function getSize( int $handle ): int { | |
/** @noinspection PhpUnhandledExceptionInspection */ | |
self::checkHandle( $handle ); | |
return strlen( self::$mem[ $handle ] ); | |
} | |
/** | |
* "Closes" the handle and releases related memory. | |
* | |
* @param int $handle The handle to be closed. | |
* | |
* @return void | |
*/ | |
public static function closeHandle( int $handle ): void { | |
/** @noinspection PhpUnhandledExceptionInspection */ | |
self::checkHandle( $handle ); | |
unset( self::$mem[ $handle ] ); | |
} | |
/** | |
* Checks if the handle is valid. | |
* | |
* @param int $handle The handle to check. | |
* | |
* @return void | |
* @throws \Exception If the handle is not valid. | |
*/ | |
public static function checkHandle( int $handle ): void { | |
if ( ! array_key_exists( $handle, self::$mem ) ) { | |
/** @noinspection PhpUnhandledExceptionInspection */ | |
throw new \Exception( "Invalid static memory handle: {$handle}" ); | |
} | |
} | |
/** | |
* Returns the internal array (for debugging). | |
* | |
* @return array The internal memory array. | |
*/ | |
public static function getMem(): array { | |
return self::$mem; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Statics; | |
/** | |
* Class MemStream | |
* | |
* A class to handle stream operations on static memory. | |
*/ | |
class MemStream { | |
/** | |
* @var mixed $context Stream context set by stream code. | |
*/ | |
public mixed $context; | |
/** | |
* @var int $position Current position in the stream. | |
*/ | |
private int $position; | |
/** | |
* @var int $handle Handle for the static memory. | |
*/ | |
private int $handle; | |
/** | |
* Opens a stream. | |
* | |
* @param string $path The path to open. | |
* @param string $mode The mode in which to open the stream. | |
* @param int $options Additional options. | |
* @param string|null $opened_path Path that was opened. | |
* @return bool True on success, false on failure. | |
* @throws \Exception If the handle is invalid. | |
*/ | |
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool { | |
$url = parse_url($path); | |
$this->handle = (int)$url["host"]; | |
try { | |
MemCache::checkHandle( $this->handle ); | |
} catch (\Exception $e) { | |
/** @noinspection PhpUnhandledExceptionInspection */ | |
throw new \Exception("Invalid staticmem stream handle: '{$path}'; expected 'staticmem://<valid_int_handle>'"); | |
} | |
$this->position = 0; | |
return true; | |
} | |
/** | |
* Reads from the stream. | |
* | |
* @param int $count Number of bytes to read. | |
* @return string The data read from the stream. | |
*/ | |
public function stream_read(int $count): string { | |
$result = MemCache::getSubstrValue($this->handle, $this->position, $count); | |
$this->position += strlen($result); | |
return $result; | |
} | |
/** | |
* Writes to the stream. | |
* | |
* @param string $data The data to write. | |
* @return int The number of bytes written. | |
*/ | |
public function stream_write(string $data): int { | |
$value=MemCache::getValue($this->handle); | |
$written=strlen($data); | |
MemCache::setValue($this->handle, | |
substr($value, 0, $this->position) | |
. $data | |
. substr($value, $this->position += $written) | |
); | |
return $written; | |
} | |
/** | |
* Returns the current position in the stream. | |
* | |
* @return int The current position. | |
*/ | |
public function stream_tell():int { | |
return $this->position; | |
} | |
/** | |
* Checks if the end of the stream has been reached. | |
* | |
* @return bool True if end of stream, false otherwise. | |
*/ | |
public function stream_eof():bool { | |
return $this->position >= MemCache::getSize($this->handle); | |
} | |
/** | |
* Seeks to a position in the stream. | |
* | |
* @param int $offset The offset to seek to. | |
* @param int $mode The mode to use for seeking. | |
* @return bool True on success, false on failure. | |
*/ | |
public function stream_seek($offset, $mode):bool { | |
$size = MemCache::getSize($this->handle); | |
switch ($mode) { | |
case SEEK_SET: $newPos = $offset; break; | |
case SEEK_CUR: $newPos = $this->position + $offset; break; | |
case SEEK_END: $newPos = $size + $offset; break; | |
default: return false; | |
} | |
$result = ($newPos >=0 && $newPos <=$size); | |
if ($result) { | |
$this->position = $newPos; | |
} | |
return $result; | |
} | |
/** | |
* Registers the stream wrapper protocol. | |
* | |
* @return void | |
* @throws \Exception If registration fails. | |
*/ | |
public static function init(): void { | |
if (!stream_wrapper_register("staticmem", "Statics\\MemStream")) { | |
/** @noinspection PhpUnhandledExceptionInspection */ | |
throw new \Exception("Failed to register staticmem:// protocol"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment