2010-01-21 19 views
2

下面是我在大約一年前發現的一個函數,它應該對memcache密鑰進行鎖定,以便您可以更新其值,而不會有任何嘗試同時更新密鑰的請求的麻煩。幫助PHP call_user_func並將函數集成到Class中?

這是非常基本的,但我可以使用一點幫助來弄清楚如何100%使用它。我不知道有關的部分是它通過在$ updateFunction,然後將其傳遞給**

call_user_func($updateFunction, $data); // update data 

我從來沒有()之前使用的call_user_func。基於這段代碼,有人可以給我一個基本的例子,說明它調用的函數可能看起來像什麼(沒有執行任何mysql或任何操作,只是它的工作方式)。我能否將多個屬性傳遞給呼叫功能?

感謝您的任何幫助。另外假設我已經有一個類名Memcache,它有一個連接或對象與這個$ this-> connection我需要改變下面的函數中的任何東西,將它添加到我的Memcache類中嗎?此外,一旦這個函數是我現有的memcache類的一部分,該回調函數是否能夠調用其他類中的方法?

希望這不是讓人困惑。

// {{{ locked_mecache_update($memcache,$key,$updateFunction,$expiryTime,$waitUTime,$maxTries) 
/** 
* A function to do ensure only one thing can update a memcache at a time. 
* 
* Note that there are issues with the $expiryTime on memcache not being 
* fine enough, but this is the best I can do. The idea behind this form 
* of locking is that it takes advantage of the fact that 
* {@link memcache_add()}'s are atomic in nature. 
* 
* It would be possible to be a more interesting limiter (say that limits 
* updates to no more than 1/second) simply by storing a timestamp or 
* something of that nature with the lock key (currently stores "1") and 
* not deleitng the memcache entry. 
* 
* @param $memcache memcache the memcache object 
* @param $key string the key to do the update on 
* @param $updateFunction mixed the function to call that accepts the data 
* from memcache and modifies it (use pass by reference). 
* @param $expiryTime integer time in seconds to allow the key to last before 
* it will expire. This should only happen if the process dies during update. 
* Choose a number big enough so that $updateFunction will take much less 
* time to execute. 
* @param $waitUTime integer the amount of time in microseconds to wait before 
* checking for the lock to release 
* @param $maxTries integer maximum number of attempts before it gives up 
* on the locks. Note that if $maxTries is 0, then it will RickRoll forever 
* (never give up). The default number ensures that it will wait for three 
* full lock cycles to crash before it gives up also. 
* @return boolean success or failure 
*/ 
function locked_memcache_update(
    $memcache,   // Memcache Object 
    $key,    // Key to update 
    $updateFunction, // Function to pass key/value into to update 
    $expiryTime=3,  // time before key expires 
    $waitUtime=101, // time to wait for to check for lock release 
    $maxTries=100000) // number of times to try to get lock 
    { 

    $lock = 'lock:'.$key; 

    // get the lock {{{ 
    if ($maxTries>0) { 
     for ($tries=0; $tries< $maxTries; ++$tries) { 
      if ($memcache->add($lock,1,0,$expiryTime)) { break; } 
      usleep($waitUtime); 
     } 
     if ($tries == $maxTries) { 
      // handle failure case (use exceptions and try-catch if you need to be nice) 
      trigger_error(sprintf('Lock failed for key: %s',$key), E_USER_NOTICE); 
      return false; 
     } 
    } else { 
     while (!$memcache->add($lock,1,0,$expiryTime)) { 
      usleep($waitUtime); 
     } 
    } 
    // }}} 

    //Now we have a lock so we can update of key/value 
    // modify data in cache {{{ 
    $data = $memcache->get($key, $flag); 
    call_user_func($updateFunction, $data); // update data 
    $memcache->set($key, $data, $flag); 
    // }}} 

    // Update complete so we release our lock 
    // clear the lock 
    $memcache->delete($lock,0); 
    return true; 
} 
// }}} 
?> 

UPDATE

這裏是我的,我想這與

<?PHP 
class MemCache 
{ 

    // Memcache object 
    public $connection; 

    function __construct() 
    { 
     $this->connection = new MemCache; 
    } 

    // Set a key/value to memcache with Expire time 
    function store($key, $data, $ttl) 
    { 
     return $this->connection->set($key, $data, 0, $ttl); 
    } 

    // Retrieve a Value from Memcache with a KEY 
    function fetch($key) 
    { 
     return $this->connection->get($key); 
    } 

    // DELETE a Key/Value from Memcache with a KEY 
    function delete($key) 
    { 
     return $this->connection->delete($key); 
    } 

    // Add a server connection to memcache 
    function addServer($host, $port = 11211, $weight = 10) 
    { 
     $this->connection->addServer($host, $port, true, $weight); 
    } 

    // Clear all memcache data 
    function flush() 
    { 
     return $this->connection->flush(); 
    } 

    // Show Memcache stats 
    function stats() 
    { 
     return statDetails($this->connection->getStats()); 
    } 

    // Show Memcache stats in a table 
    function statDetails($status) 
    { 
     echo "<table border='1'>"; 
     echo "<tr><td>Memcache Server version:</td><td> " . $status["version"] . 
      "</td></tr>"; 
     echo "<tr><td>Process id of this server process </td><td>" . $status["pid"] . 
      "</td></tr>"; 
     echo "<tr><td>Number of seconds this server has been running </td><td>" . $status["uptime"] . 
      "</td></tr>"; 
     echo "<tr><td>Accumulated user time for this process </td><td>" . $status["rusage_user"] . 
      " seconds</td></tr>"; 
     echo "<tr><td>Accumulated system time for this process </td><td>" . $status["rusage_system"] . 
      " seconds</td></tr>"; 
     echo "<tr><td>Total number of items stored by this server ever since it started </td><td>" . 
      $status["total_items"] . "</td></tr>"; 
     echo "<tr><td>Number of open connections </td><td>" . $status["curr_connections"] . 
      "</td></tr>"; 
     echo "<tr><td>Total number of connections opened since the server started running </td><td>" . 
      $status["total_connections"] . "</td></tr>"; 
     echo "<tr><td>Number of connection structures allocated by the server </td><td>" . 
      $status["connection_structures"] . "</td></tr>"; 
     echo "<tr><td>Cumulative number of retrieval requests </td><td>" . $status["cmd_get"] . 
      "</td></tr>"; 
     echo "<tr><td> Cumulative number of storage requests </td><td>" . $status["cmd_set"] . 
      "</td></tr>"; 
     $percCacheHit = ((real)$status["get_hits"]/(real)$status["cmd_get"] * 100); 
     $percCacheHit = round($percCacheHit, 3); 
     $percCacheMiss = 100 - $percCacheHit; 
     echo "<tr><td>Number of keys that have been requested and found present </td><td>" . 
      $status["get_hits"] . " ($percCacheHit%)</td></tr>"; 
     echo "<tr><td>Number of items that have been requested and not found </td><td>" . 
      $status["get_misses"] . "($percCacheMiss%)</td></tr>"; 
     $MBRead = (real)$status["bytes_read"]/(1024 * 1024); 
     echo "<tr><td>Total number of bytes read by this server from network </td><td>" . 
      $MBRead . " Mega Bytes</td></tr>"; 
     $MBWrite = (real)$status["bytes_written"]/(1024 * 1024); 
     echo "<tr><td>Total number of bytes sent by this server to network </td><td>" . 
      $MBWrite . " Mega Bytes</td></tr>"; 
     $MBSize = (real)$status["limit_maxbytes"]/(1024 * 1024); 
     echo "<tr><td>Number of bytes this server is allowed to use for storage.</td><td>" . 
      $MBSize . " Mega Bytes</td></tr>"; 
     echo "<tr><td>Number of valid items removed from cache to free memory for new items.</td><td>" . 
      $status["evictions"] . "</td></tr>"; 
     echo "</table>"; 
    } 

} 

?> 

回答

2

documentation of call_user_func()整合現有的內存緩存類包含一個鏈接callback pseudo-type。簡而言之,它是一個函數名稱或一個數組。該數組必須包含兩個字符串(一個類名稱和一個函數名稱 - 對靜態函數的回調)或一個對象和一個字符串(一個對象以及對該對象調用的方法 - 用於成員函數)。下面是從文檔的例子:

<?php 

// An example callback function 
function my_callback_function() { 
    echo 'hello world!'; 
} 

// An example callback method 
class MyClass { 
    static function myCallbackMethod() { 
     echo 'Hello World!'; 
    } 
} 

// Type 1: Simple callback 
call_user_func('my_callback_function'); 


// Type 2: Static class method call 
call_user_func(array('MyClass', 'myCallbackMethod')); 

// Type 3: Object method call 
$obj = new MyClass(); 
call_user_func(array($obj, 'myCallbackMethod')); 

// Type 4: Static class method call (As of PHP 5.2.3) 
call_user_func('MyClass::myCallbackMethod'); 

// Type 5: Relative static class method call (As of PHP 5.3.0) 
class A { 
    public static function who() { 
     echo "A\n"; 
    } 
} 

class B extends A { 
    public static function who() { 
     echo "B\n"; 
    } 
} 

call_user_func(array('B', 'parent::who')); // A 
?> 

一件事:你鎖定可能是add($lock,...get()之間interrupted。使用increment()decrement()可以解決這個問題。

+0

我正在閱讀increment()和decrement()我不確定如何在這裏使用它們,你能解釋一下它們如何用於幫助鎖定嗎? – JasonDavis

+0

'如果增量($ lock)!= 1',則該對象已被鎖定,使用'decrement($ lock)'恢復。否則,你成功獲得鎖並可以執行操作並調用'decrement()'來再次釋放鎖。這裏的關鍵是'increment()'和'decrement()'都是原子操作,它們讀取*和*連續寫入值而不會中斷。 – soulmerge

1

沒有直接回答,但值得注意的是,你實際上並不需要使用call_user_func - 你可以調用一個變量函數:

function ham($jam) { 
    echo $jam; 
} 

$bar = 'eggs'; 
$foo = 'ham'; 

$foo($bar); 

這應該做工精細的實例化對象了:

$bees->$honey($sting); 

還有更多的信息在docs