您的当前位置:首页>全部文章>文章详情

php文件锁

发表于:2024-04-19 16:07:29浏览:133次TAG: #PHP #文件锁

前言

本文将详细介绍PHP如何通过文件锁来解决并发问题,并提供整理的源码和通过示例代码进行说明。

示例

// 调用示例
// 加锁
$lock_key = 'xxxx';
if (!\app\common\utils\Lock::lockUp($lock_key)) {
    // 终止操作,已经有别的进程在执行了
    return '';
}
// TODO
// 执行业务操作...
// 解锁
\app\common\utils\Lock::unLock($lock_key);

<?php

namespace app\common\utils;

/**
 * 文件锁
 */
class Lock
{
    // 文件锁资源树
    static $resource = [];
    /**
     * 加锁
     * 测试结果:同个浏览器开2个请求,非阻塞无效;开2个浏览器请求,非阻塞有效
     * flock默认是阻塞锁,阻塞模式,程序会一直等待。
     * LOCK_EX 排它锁
     * LOCK_NB 非阻塞,如果文件被占用直接返回false
     * @param $uniqueId
     * @return bool false=操作过于频繁,终止;true=可以执行
     */
    public static function lockUp($uniqueId)
    {
        static::$resource[$uniqueId] = fopen(static::getFilePath($uniqueId), 'w+');
        return flock(static::$resource[$uniqueId], LOCK_EX | LOCK_NB);
    }

    /**
     * 解锁
     * @param $uniqueId
     * @return bool
     */
    public static function unLock($uniqueId)
    {
        if (!isset(static::$resource[$uniqueId])) return false;
        flock(static::$resource[$uniqueId], LOCK_UN);
        fclose(static::$resource[$uniqueId]);
        return static::deleteFile($uniqueId);
    }

    /**
     * 获取锁文件的路径
     *
     * @param $uniqueId
     * @return string
     */
    private static function getFilePath($uniqueId)
    {
        //tp6:$dirPath = app()->getRuntimePath(). 'lock/'
        //tp5:$dirPath = RUNTIME_PATH. 'lock/';
        //当前目录:$dirPath = __DIR__ . '/lock/';
        //网站入口目录:$dirPath = getcwd() . '/lock/';
        $dirPath = getcwd() . '/lock/';
        !is_dir($dirPath) && mkdir($dirPath, 0755, true);
        return $dirPath . md5($uniqueId) . '.lock';
    }

    /**
     * 删除锁文件
     * @param $uniqueId
     * @return bool
     */
    private static function deleteFile($uniqueId)
    {
        $filePath = static::getFilePath($uniqueId);
        return file_exists($filePath) && unlink($filePath);
    }
}