如何用PHP项目操作Redis?

wen java案例 3

本文目录导读:

如何用PHP项目操作Redis?

  1. 安装Redis扩展
  2. 连接Redis
  3. 基本操作
  4. 高级功能
  5. 实际应用示例
  6. 性能优化建议
  7. 错误处理

我来详细介绍在PHP项目中操作Redis的方法:

安装Redis扩展

使用PECL安装

pecl install redis

编译安装

# 下载扩展
wget https://github.com/phpredis/phpredis/archive/develop.zip
unzip develop.zip
cd phpredis-develop
# 编译安装
phpize
./configure
make && make install
# 在php.ini中添加
extension=redis.so

Composer安装(推荐)

{
    "require": {
        "predis/predis": "^2.0"
    }
}

连接Redis

基本连接

<?php
// 使用phpredis扩展(面向对象方式)
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('password'); // 如果有密码
// 使用Predis库
require 'vendor/autoload.php';
$client = new Predis\Client([
    'scheme' => 'tcp',
    'host'   => '127.0.0.1',
    'port'   => 6379,
    'password' => 'password' // 可选
]);

连接池配置

// 使用长连接
$redis->pconnect('127.0.0.1', 6379);
// 设置连接池参数
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$redis->setOption(Redis::OPT_PREFIX, 'myapp:');

基本操作

字符串操作

// 设置值
$redis->set('key', 'value');
$redis->setex('key_expire', 3600, 'value'); // 设置过期时间(秒)
$redis->setnx('key', 'value'); // 仅当key不存在时设置
// 获取值
$value = $redis->get('key');
// 批量操作
$redis->mset(['key1' => 'val1', 'key2' => 'val2']);
$values = $redis->mget(['key1', 'key2']);
// 递增递减
$redis->incr('counter');
$redis->incrBy('counter', 10);
$redis->decr('counter');

哈希操作

// 设置哈希字段
$redis->hSet('user:1', 'name', '张三');
$redis->hMSet('user:1', [
    'name' => '张三',
    'age' => 25,
    'city' => '北京'
]);
// 获取哈希字段
$name = $redis->hGet('user:1', 'name');
$user = $redis->hGetAll('user:1');
$fields = $redis->hMGet('user:1', ['name', 'age']);
// 检查字段是否存在
$exists = $redis->hExists('user:1', 'name');
// 删除字段
$redis->hDel('user:1', 'age');
// 获取所有字段
$keys = $redis->hKeys('user:1');
$values = $redis->hVals('user:1');

列表操作

// 左/右插入
$redis->lPush('tasks', 'task1');
$redis->rPush('tasks', 'task2');
// 左/右弹出
$task = $redis->lPop('tasks');
$task = $redis->rPop('tasks');
// 获取列表长度
$length = $redis->lLen('tasks');
// 获取范围内元素
$tasks = $redis->lRange('tasks', 0, -1);
// 阻塞弹出(带超时)
$task = $redis->blPop(['tasks'], 5); // 等待5秒

集合操作

// 添加元素
$redis->sAdd('users:online', 'user1', 'user2');
// 检查成员
$isMember = $redis->sIsMember('users:online', 'user1');
// 获取所有成员
$members = $redis->sMembers('users:online');
// 集合运算
$redis->sAdd('set1', 'a', 'b', 'c');
$redis->sAdd('set2', 'b', 'c', 'd');
$union = $redis->sUnion('set1', 'set2');      // 并集
$intersect = $redis->sInter('set1', 'set2');   // 交集
$diff = $redis->sDiff('set1', 'set2');         // 差集

有序集合操作

// 添加分数成员
$redis->zAdd('scores', 100, 'Alice');
$redis->zAdd('scores', 90, 'Bob');
// 获取排名
$rank = $redis->zRank('scores', 'Alice');     // 升序
$rank = $redis->zRevRank('scores', 'Alice');  // 降序
// 获取范围内的成员
$top3 = $redis->zRevRange('scores', 0, 2, true);
// 增加分数
$redis->zIncrBy('scores', 10, 'Bob');
// 获取分数
$score = $redis->zScore('scores', 'Bob');

高级功能

事务处理

// 方式一:multi/exec
$redis->multi();
$redis->set('key1', 'value1');
$redis->set('key2', 'value2');
$redis->incr('counter');
$result = $redis->exec(); // 执行事务
// 方式二:discard(取消事务)
$redis->multi();
$redis->set('key1', 'value1');
$redis->discard(); // 取消事务
// 乐观锁(watch)
$redis->watch('stock');
$stock = $redis->get('stock');
if ($stock > 0) {
    $redis->multi();
    $redis->decr('stock');
    $redis->exec();
}

管道操作

// 批量发送命令,提高性能
$redis->pipeline();
$redis->set('key1', 'value1');
$redis->set('key2', 'value2');
$redis->set('key3', 'value3');
$results = $redis->exec();

发布/订阅

// 发布者
$redis->publish('channel', 'message');
// 订阅者(需要单独脚本)
$redis->subscribe(['channel'], function($redis, $channel, $message) {
    echo "收到消息: $message\n";
});

Lua脚本

// 原子性脚本执行
$lua = <<<'SCRIPT'
    local current = redis.call('GET', KEYS[1])
    if not current then
        return redis.error_reply('Key not found')
    end
    if tonumber(current) > tonumber(ARGV[1]) then
        return redis.error_reply('Value is too large')
    end
    return redis.call('INCR', KEYS[1])
SCRIPT;
$result = $redis->eval($lua, ['counter', '10'], 1);

实际应用示例

缓存实现

class CacheService {
    private $redis;
    private $ttl = 3600; // 默认1小时
    public function __construct() {
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }
    public function get($key, $callback = null) {
        $value = $this->redis->get($key);
        if ($value === false && $callback) {
            $value = $callback();
            $this->set($key, $value);
        }
        return $value;
    }
    public function set($key, $value, $ttl = null) {
        $ttl = $ttl ?? $this->ttl;
        return $this->redis->setex($key, $ttl, $value);
    }
    public function delete($key) {
        return $this->redis->del($key);
    }
    public function clear($pattern = '*') {
        $keys = $this->redis->keys($pattern);
        if (!empty($keys)) {
            return $this->redis->del($keys);
        }
        return 0;
    }
}

分布式锁

class RedisLock {
    private $redis;
    private $lockTime = 10; // 锁超时时间(秒)
    public function __construct() {
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }
    public function acquire($key, $requestId) {
        $result = $this->redis->set(
            "lock:$key",
            $requestId,
            ['NX', 'EX' => $this->lockTime]
        );
        return $result !== false;
    }
    public function release($key, $requestId) {
        $script = <<<'LUA'
            if redis.call("get",KEYS[1]) == ARGV[1] then
                return redis.call("del",KEYS[1])
            else
                return 0
            end
LUA;
        return $this->redis->eval($script, ["lock:$key", $requestId], 1);
    }
}

用户会话管理

class SessionManager {
    private $redis;
    private $sessionPrefix = 'session:';
    private $sessionTimeout = 1800; // 30分钟
    public function __construct() {
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }
    public function createSession($userId, $data = []) {
        $sessionId = bin2hex(random_bytes(32));
        $key = $this->sessionPrefix . $sessionId;
        $data['user_id'] = $userId;
        $data['created_at'] = time();
        $this->redis->hMSet($key, $data);
        $this->redis->expire($key, $this->sessionTimeout);
        return $sessionId;
    }
    public function getSession($sessionId) {
        $key = $this->sessionPrefix . $sessionId;
        $data = $this->redis->hGetAll($key);
        if (!empty($data)) {
            $this->redis->expire($key, $this->sessionTimeout); // 续期
        }
        return $data;
    }
    public function destroySession($sessionId) {
        return $this->redis->del($this->sessionPrefix . $sessionId);
    }
}

性能优化建议

// 1. 使用长连接
$redis = new Redis();
$redis->pconnect('127.0.0.1', 6379, 2.5); // 2.5秒超时
// 2. 批量操作代替循环
// 不推荐
foreach ($items as $key => $value) {
    $redis->set($key, $value);
}
// 推荐
$pipe = $redis->pipeline();
foreach ($items as $key => $value) {
    $pipe->set($key, $value);
}
$pipe->exec();
// 3. 使用scan代替keys(大数据量时)
$iterator = null;
while ($keys = $redis->scan($iterator, 'pattern:*')) {
    foreach ($keys as $key) {
        // 处理key
    }
}
// 4. 合理设置序列化
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);

错误处理

try {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $redis->set('test', 'value');
} catch (RedisException $e) {
    // 连接失败或操作异常
    error_log("Redis error: " . $e->getMessage());
    // 重试逻辑
    if ($e->getCode() == 0) { // 连接错误
        sleep(1);
        $redis->connect('127.0.0.1', 6379);
    }
} finally {
    if (isset($redis)) {
        $redis->close();
    }
}

这些是PHP操作Redis的核心内容,根据项目需求选择合适的扩展库和实现方式,注意性能优化和错误处理。

抱歉,评论功能暂时关闭!