php常用类或方法

原创 · 金汉江 · 2023-12-05
PHP

简单数据库查询封装

class MyDb {
    private $mysqli=NULL;
    function __construct($dbname) {
        $configs = [
            'dbname1'=>['xxx.xxx.com', 'user', 'pass', 'dbname1'],
        ];
        if(! isset($configs[$dbname])) {
            throw new Exception('未查询到DB');
        }
        list($host, $user ,$pass, $dname) = $configs[$dbname];
        // print_r($host);die;
        $this->mysqli = new \mysqli($host, $user, $pass, $dname, 3306);
        $this->mysqli->set_charset('utf8mb4');
    }
    public function query($sql)
    {
        // echo $sql.PHP_EOL.PHP_EOL;
        if(preg_match('/^delete/i', $sql)) return [];
        if(preg_match('/^update/i', $sql)) return [];
        $stmt = $this->mysqli->query($sql); $result = [];
        if($stmt && preg_match('/^select/i', $sql)) {
            $result = [];
            while($obj = $stmt->fetch_assoc()) {
                $result[] = $obj;
            }
        } else {
            $result = $stmt;
        }
        return $result;
    }
}

常用调用方法

// 输出变量简写
function pr(...$texts) {
    echo '<pre>';
    if(is_array($texts)) {
        foreach($texts as $text) { print_r($text); }
    } else {
        print_r($texts);
    }
    die();
}
// 写文件日志简写
function pw(...$texts) {
    $traces = debug_backtrace(); $last = $traces[0];
    if(is_array($texts)) {
        foreach($texts as $text) { 
            file_put_contents(dirname($last['file']).'/1.log', basename($last['file']).'->'.$last['line'].'->'.print_r($text, 1).PHP_EOL, 8);
        }
    } else {
        file_put_contents(dirname($last['file']).'/1.log', basename($last['file']).'->'.$last['line'].'->'.print_r($text, 1).PHP_EOL, 8);
    }
}

分表数据处理

数据库表拆成100张表,如果要对其中的数据做处理

$db = new MyDb('dbname');
for($i = 0; $i < 100; $i ++)
{
    $lastId = 0; $limit = 100;
    while(true)
    {
        // id>{$lastId} ORDER by id asc limit {$limit} 不能省略修改
        $objs = $db->query(
            "select * from Product_{$i} where id>{$lastId} ORDER by id asc limit {$limit}");
        if(($ct = count($objs)) > 0)
        {
            foreach($objs as $obj)
            {
                // 取出的数据做业务处理

            }
            if($ct < $limit) break; // 小于$limit数,则数据取完
            $lastId = $obj->id;
            usleep(mt_rand(1000, 1000000));
        }
        else
        {
            break;
        }
    }
}

多进程调试

经常需要启动多个进程来调试, 可以使用以下代码

首先要确认开启pcntl模块, 且只能在linux环境下执行
启动100个子进程,并发查询数据库

$childs = array();
for($j = 0; $j < 100; $j++)
{
    $pid = pcntl_fork();
    if($pid == -1) die('Could not fork!');

    if($pid) { // 父进程
        echo "parent \n";
        $childs[] = $pid;
    } else {

        // 这里子进程执行任务
        $db = new MyDb('xxxx');
        for($i = 0; $i< 1000; $i++) {
            $db->query('/*slave*/select now()');
            usleep(500);
        }

        exit();
    }
}

while(count($childs) > 0) {
    foreach($childs as $k=>$pid) {
        // WNOHANG参数表示非阻塞等待,即如果没有子进程退出,则立即返回
        $res = pcntl_waitpid($pid, $status, WNOHANG);
        if($res == -1 || $res > 0) {
            unset($childs[$k]);
        }
    }
    sleep(1);
}

快速导出大量数据

$sql = 'select * from user';
$pdo = new \PDO( 'mysql:host=127.0.0.1;dbname=test', 'root', 'root' );
$pdo->setAttribute( \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$rows = $pdo->query($sql);

$filename = date('Ymd').'.csv';//设置文件名
header('Content-Type:text/csv');
header("Content-Disposition:attachment;filename={$filename}");
$out = fopen('php://output','w');
// 写入标题
fputcsv(
    $out, [
        'id',
        'username',
        'password',
        'create_time'
    ]
);

foreach( $rows as $row ){
    $line=[
        $row['id'],
        $row['username'],
        $row['password'],
        $row['create_time']
    ];
    fputcsv($out, $line);
}

fclose($out);
$memory=round((memory_get_usage()-$startMemory)/1024/1024,3).'M'.PHP_EOL;
file_put_contents('/tmp/test.txt',$memory,FILE_APPEND);