SimpleSHM 是一個較小的抽象層,用於使用 PHP 操作共享記憶體,支援以一種物件導向的方式輕鬆操作記憶體段。在編寫使用共享記憶體進行儲存的小型應用程式時,這個庫可幫助建立非常簡潔的程式碼。可以使用 3 個方法進行處理:讀、寫和刪除。從該類中簡單地例項化一個物件,可以控制開啟的共享記憶體段。
類物件和測試程式碼
<?php
//類物件
namespace Simple\SHM;
class Block
{
/**
* Holds the system id for the shared memory block
*
* @var int
* @access protected
*/
protected $id;
/**
* Holds the shared memory block id returned by shmop_open
*
* @var int
* @access protected
*/
protected $shmid;
/**
* Holds the default permission (octal) that will be used in created memory blocks
*
* @var int
* @access protected
*/
protected $perms = 0644;
/**
* Shared memory block instantiation
*
* In the constructor we'll check if the block we're going to manipulate
* already exists or needs to be created. If it exists, let's open it.
*
* @access public
* @param string $id (optional) ID of the shared memory block you want to manipulate
*/
public function __construct($id = null)
{
if($id === null) {
$this->id = $this->generateID();
} else {
$this->id = $id;
}
if($this->exists($this->id)) {
$this->shmid = shmop_open($this->id, "w", 0, 0);
}
}
/**
* Generates a random ID for a shared memory block
*
* @access protected
* @return int System V IPC key generated from pathname and a project identifier
*/
protected function generateID()
{
$id = ftok(__FILE__, "b");
return $id;
}
/**
* Checks if a shared memory block with the provided id exists or not
*
* In order to check for shared memory existance, we have to open it with
* reading access. If it doesn't exist, warnings will be cast, therefore we
* suppress those with the @ operator.
*
* @access public
* @param string $id ID of the shared memory block you want to check
* @return boolean True if the block exists, false if it doesn't
*/
public function exists($id)
{
$status = @shmop_open($id, "a", 0, 0);
return $status;
}
/**
* Writes on a shared memory block
*
* First we check for the block existance, and if it doesn't, we'll create it. Now, if the
* block already exists, we need to delete it and create it again with a new byte allocation that
* matches the size of the data that we want to write there. We mark for deletion, close the semaphore
* and create it again.
*
* @access public
* @param string $data The data that you wan't to write into the shared memory block
*/
public function write($data)
{
$size = mb_strlen($data, 'UTF-8');
if($this->exists($this->id)) {
shmop_delete($this->shmid);
shmop_close($this->shmid);
$this->shmid = shmop_open($this->id, "c", $this->perms, $size);
shmop_write($this->shmid, $data, 0);
} else {
$this->shmid = shmop_open($this->id, "c", $this->perms, $size);
shmop_write($this->shmid, $data, 0);
}
}
/**
* Reads from a shared memory block
*
* @access public
* @return string The data read from the shared memory block
*/
public function read()
{
$size = shmop_size($this->shmid);
$data = shmop_read($this->shmid, 0, $size);
return $data;
}
/**
* Mark a shared memory block for deletion
*
* @access public
*/
public function delete()
{
shmop_delete($this->shmid);
}
/**
* Gets the current shared memory block id
*
* @access public
*/
public function getId()
{
return $this->id;
}
/**
* Gets the current shared memory block permissions
*
* @access public
*/
public function getPermissions()
{
return $this->perms;
}
/**
* Sets the default permission (octal) that will be used in created memory blocks
*
* @access public
* @param string $perms Permissions, in octal form
*/
public function setPermissions($perms)
{
$this->perms = $perms;
}
/**
* Closes the shared memory block and stops manipulation
*
* @access public
*/
public function __destruct()
{
shmop_close($this->shmid);
}
}
<?php
//測試使用程式碼
namespace Simple\SHM\Test;
use Simple\SHM\Block;
class BlockTest extends \PHPUnit_Framework_TestCase
{
public function testIsCreatingNewBlock()
{
$memory = new Block;
$this->assertInstanceOf('Simple\\SHM\\Block', $memory);
$memory->write('Sample');
$data = $memory->read();
$this->assertEquals('Sample', $data);
}
public function testIsCreatingNewBlockWithId()
{
$memory = new Block(897);
$this->assertInstanceOf('Simple\\SHM\\Block', $memory);
$this->assertEquals(897, $memory->getId());
$memory->write('Sample 2');
$data = $memory->read();
$this->assertEquals('Sample 2', $data);
}
public function testIsMarkingBlockForDeletion()
{
$memory = new Block(897);
$memory->delete();
$data = $memory->read();
$this->assertEquals('Sample 2', $data);
}
public function testIsPersistingNewBlockWithoutId()
{
$memory = new Block;
$this->assertInstanceOf('Simple\\SHM\\Block', $memory);
$memory->write('Sample 3');
unset($memory);
$memory = new Block;
$data = $memory->read();
$this->assertEquals('Sample 3', $data);
}
}
額外說明
<?php
$memory = new SimpleSHM;
$memory->write('Sample');
echo $memory->read();
?>
請注意,上面程式碼裡沒有為該類傳遞一個 ID。如果沒有傳遞 ID,它將隨機選擇一個編號並開啟該編號的新記憶體段。我們可以以引數的形式傳遞一個編號,供建構函式開啟現有的記憶體段,或者建立一個具有特定 ID 的記憶體段,如下
<?php
$new = new SimpleSHM(897);
$new->write('Sample');
echo $new->read();
?>
神奇的方法 __destructor
負責在該記憶體段上呼叫 shmop_close
來取消設定物件,以與該記憶體段分離。我們將這稱為 “SimpleSHM 101”。現在讓我們將此方法用於更高階的用途:使用共享記憶體作為儲存。儲存資料集需要序列化,因為陣列或物件無法儲存在記憶體中。儘管這裡使用了 JSON 來序列化,但任何其他方法(比如 XML 或內建的 PHP 序列化功能)也已足夠。如下
<?php
require('SimpleSHM.class.php');
$results = array(
'user' => 'John',
'password' => '123456',
'posts' => array('My name is John', 'My name is not John')
);
$data = json_encode($results);
$memory = new SimpleSHM;
$memory->write($data);
$storedarray = json_decode($memory->read());
print_r($storedarray);
?>
我們成功地將一個陣列序列化為一個 JSON 字串,將它儲存在共享記憶體塊中,從中讀取資料,去序列化 JSON 字串,並顯示儲存的陣列。這看起來很簡單,但請想象一下這個程式碼片段帶來的可能性。您可以使用它儲存 Web 服務請求、資料庫查詢或者甚至模板引擎快取的結果。在記憶體中讀取和寫入將帶來比在磁碟中讀取和寫入更高的效能。
使用此儲存技術不僅對快取有用,也對應用程式之間的資料交換也有用,只要資料以兩端都可讀的格式儲存。不要低估共享記憶體在 Web 應用程式中的力量。可採用許多不同的方式來巧妙地實現這種儲存,惟一的限制是開發人員的創造力和技能。