Memcached::cas

(PECL memcached >= 0.1.0)

Memcached::cas比较并交换值

说明

public bool Memcached::cas ( float $cas_token , string $key , mixed $value [, int $expiration ] )

Memcached::cas()执行一个"检查并设置"的操作,因此,它仅在当前客户端最后一次取值后,该key 对应的值没有被其他客户端修改的情况下, 才能够将值写入。检查是通过cas_token参数进行的, 这个参数是Memcach指定给已经存在的元素的一个唯一的64位值, 怎样获取这个值请查看Memcached::get*() 系列方法的文档。注意:这个值作为double类型是因为PHP的整型空间限制。

译注:这是Memcached扩展比Memcache扩展一个非常重要的优势, 在这样一个系统级(Memcache自身提供)的冲突检测机制(乐观锁)下, 我们才能保证高并发下的数据安全。

参数

cas_token

与已存在元素关联的唯一的值,由Memcache生成。

key

用于存储值的键名。

value

存储的值。

expiration

到期时间,默认为 0。 更多信息请参见到期时间

返回值

成功时返回 TRUE, 或者在失败时返回 FALSE。 如果在元素尝试存储时发现在本客户端最后一次获取后被其他客户端修改,Memcached::getResultCode() 将返回Memcached::RES_DATA_EXISTS

范例

Example #1 Memcached::cas() 示例

<?php
$m 
= new Memcached();
$m->addServer('localhost'11211);

do {
    
/* 获取ip列表以及它的标记 */
    
$ips $m->get('ip_block'null$cas);
    
/* 如果列表不存在, 创建并进行一个原子添加(如果其他客户端已经添加, 这里就返回false)*/
    
if ($m->getResultCode() == Memcached::RES_NOTFOUND) {
        
$ips = array($_SERVER['REMOTE_ADDR']);
        
$m->add('ip_block'$ips);
    
/* 其他情况下,添加ip到列表中, 并以cas方式去存储, 这样当其他客户端修改过, 则返回false */
    
} else { 
        
$ips[] = $_SERVER['REMOTE_ADDR'];
        
$m->cas($cas'ip_block'$ips);
    }   
} while (
$m->getResultCode() != Memcached::RES_SUCCESS);

?>

参见

User Contributed Notes

Haravikk 19-Aug-2017 04:26
I'm not sure whether this remains true in the newer versions of the Memcached module (v3.0 onwards) but in the version shipped with PHP 5.6 the return value and result code when using this method with OPT_BINARY_PROTOCOL enabled are entirely useless.

Setting a value successful may return true, with a result code of RES_END, but it may also return true with a result code of RES_SUCCESS.

However, *unsuccessfully* setting a value likewise seems to return true and RES_SUCCESS, effectively rendering this function's return value useless with the binary protocol enabled as it is impossible to distinguish success from failure.

If you need to rely on the return value of this method then I strongly recommend disabling the binary protocol under PHP 5.6, as in its current state the common memcached module is too broken otherwise for CAS usage.

Hopefully someone else can weigh in on whether this is still broken in newer versions or not.
php at sergentet dot fr 25-May-2017 06:59
To prevent a perpetual loop on any Memcached error, you can add a simple counter :

$security_count = 0;

do {
        //[]....
        $security_loop++
        if ($security_loop > 10) {
                break;     //( or return "your return value" on a function )
        }
} while ($m->getResultCode() != Memcached::RES_SUCCESS);
sparcbr at gmail dot com 12-Oct-2016 01:11
Do not check command success in a while loop with something like

   
$memCached->getResultCode() != Memcached::RES_SUCCESS

Memcached::RES_SERVER_ERROR or anything like this and your script will loop forev
abodera at gmail dot com 27-Apr-2010 10:19
Watch out!

When using binary protocol, the expected result after cas() is 21 (Memcached::RES_END).

For example, to make the above example #1 work with binary protocol, use the following:
<?php
$m
= new Memcached();
$m->addServer('localhost', 11211);
$m->setOption(Memcached::OPT_BINARY_PROTOCOL,true)

// [...]

   
} else {
       
$ips[] = $_SERVER['REMOTE_ADDR'];
       
$m->cas($cas, 'ip_block', $ips);
    }  
} while (
$m->getResultCode() != Memcached::RES_END);
?>