PHP

一篇mysql的pdo操作类(阻塞)

字号+ 编辑: 种花家 修订: 种花家 来源: 原创 2023-09-11 我要说两句(1)

php调用mysql专用的pdo操作类代码。适用yaf

此代码身经百战, 使用简便。操作类启用了强类型检查, 代码在下方, 注意需要配合另外4个类文件来执行:

1 Mysql连接操作类 http://www.wkwkk.com/article/a361f53d66945efef0bc33141dbdb165.html

2 用于配套缓存和错误日志的Redis连接操作类(阻塞) http://www.wkwkk.com/article/7f9260987a3d040b4068dcc386500e61.html

3 Sql语句状态缓存类 http://www.wkwkk.com/article/7f9260987a3d040b4068dcc386500e61.html 下方可见

4 基本连接配置和模型实例分配类案例 http://www.wkwkk.com/article/98a742396c78db8ed15c32649c70e9c4.html

代码如下

<?php

declare(strict_types=1);

namespace Lightpdo;

use Lightredis\Worker as RedisWorker;

/**
 * fpm版连贯操作类
 * @package  orm
 * @subpackage mysql
 * @author  qinchao <castor@happycoworker.com>
 * @since  20160811
 * @version  20230602
 */

if (WORKMODE != 'fpm') {
    return;
}

class Worker
{
    private $_mysql_handler;
    private $_prefix;

    // redis 连接配置
 private $_redis_config = [];

    // log开关 支持参数: 0=关闭, 1=redis
 private $_log = 0;

    private $_state; // 状态容器

 private static $_instance = [];

    /**
  * 单例
  * @param array $config
  * @return mixed
  */
 public static function instance(array $config)
    {
        $hash = substr(md5($config['host'] . $config['port'] . $config['dbname'] . $config['user']), 8, 16);
        if (empty(static::$_instance[$hash]) || !array_key_exists($hash, static::$_instance)) {
            static::$_instance[$hash] = new static($config);
        }

        static::$_instance[$hash]->_state = new State();
        return static::$_instance[$hash];
    }

    public function __construct(array $config)
    {
        if (isset($config['transaction']) && $config['transaction']) {
            $this->_mysql_handler = new ConnectionHandler($config);
        } else {
            $this->_mysql_handler = ConnectionHandler::instance($config);
        }

        $this->_state = new State();

        $this->_prefix = isset($config['prefix']) ? $config['prefix'] : '';
        $this->_log = isset($config['log']) ? $config['log'] : 0;
        $this->_initRedisConfig($config);
    }

    private function _initRedisConfig(array $config)
    {
        $this->_redis_config = [
            'ip' => isset($config['redis_ip']) ? $config['redis_ip'] : '127.0.0.1',
            'port' => isset($config['redis_port']) ? (int)$config['redis_port'] : 6379,
            'auth' => isset($config['redis_auth']) ? $config['redis_auth'] : '',
            'db' => isset($config['redis_db']) ? (int)$config['redis_db'] : 8,
            'log' => isset($config['redis_log']) ? (int)$config['redis_log'] : 4,
        ];
    }

    /**
  * @desc 初始化sql状态存储对象
  * @access private
  * @return void
  */
 private function _init_sqlstatement()
    {
        if ($this->_state === null) {
            $this->_state = new State();
        }
    }

    /**
  * @desc 断线重连
  * @access private
  * @return void
  */
 private function _reconnect()
    {
        $this->_mysql_handler->pdo_instance = $this->_mysql_handler->reconnect();
    }

    /**
  * @desc 启动事务
  * @access public
  * @return self
  */
 public function transaction(): self
 {
        $this->_mysql_handler->pdo_instance->beginTransaction();
        return $this;
    }

    /**
  * 提交事务
  * @access public
  * @return void
  */
 public function commit()
    {
        $this->_mysql_handler->pdo_instance->commit();
        $this->close();
    }

    /**
  * 撤销事务,回滚
  * @access public
  * @return void
  */
 public function rollback()
    {
        $this->_mysql_handler->pdo_instance->rollback();
        $this->close();
    }

    /**
  * @desc 选择字段
  * @access public
  * @return self
  */
 public function select(): self
 {
        $this->_init_sqlstatement();

        $this->_state->query_type = 1;

        $numOfArgs = func_num_args();
        if ($numOfArgs == 0 || trim((string)func_get_arg(0)) == '') {
            $this->_state->field = '*';
        } else {
            $selectField = &$this->_state->field;
            if (is_array(func_get_arg(0))) {
                foreach (func_get_arg(0) as $v) {
                    $selectField .= $v . ',';
                }
            } else {
                for ($i = 0; $i < $numOfArgs; $i++) {
                    $selectField .= ',' . func_get_arg($i);
                }
            }
            $selectField = ltrim($selectField, ',');
        }

        return $this;
    }

    /**
  * @desc 选择数据表
  * @param string|array $table 表名/表名数组[表1名=>别名1,表2名=>别名2,...]
  * @param string $alias 表别名
  */
 public function from($table, string $alias = ''): self
 {
        $this->_init_sqlstatement();

        if (is_array($table)) {
            $clause = '';
            foreach ($table as $k => $v) {
                $clause .= ', ' . trim($this->_prefix . trim($k) . ' ' . $v);
            }
            $this->_state->table = ltrim($clause, ', ');
        } else {
            $this->_state->table = trim($this->_prefix . trim((string)$table) . ' ' . $alias);
        }
        return $this;
    }

    /**
  * @desc 左联表
  * @access public
  * @param string $table 表名
  * @param string $alias 表别名
  * @param string $case 关联条件
  * @return self
  */
 public function leftJoin(string $table, string $alias, string $case): self
 {
        $this->_state->join .= ' LEFT JOIN `' . $this->_prefix . trim($table) . '` AS ' . $alias . ' ON ' . $case;
        return $this;
    }

    /**
  * @desc 内联表
  * @access public
  * @param string $table 表名
  * @param string $alias 表别名
  * @param string $case 关联条件
  * @return self
  */
 public function join(string $table, string $alias, string $case): self
 {
        $this->_state->join .= ' INNER JOIN `' . $this->_prefix . trim($table) . '` AS ' . $alias . ' ON ' . $case;
        return $this;
    }

    /**
  * @desc 右联表
  * @access public
  * @return self
  */
 public function rightJoin(string $table, string $alias, string $case): self
 {
        $this->_state->join .= ' RIGHT JOIN `' . $this->_prefix . trim($table) . '` AS ' . $alias . ' ON ' . $case;
        return $this;
    }

    /**
  * @desc 内联表
  * @access public
  * @param string $table 表名
  * @param string $alias 表别名
  * @param string $case 关联条件
  * @return self
  */
 public function innerJoin(string $table, string $alias, string $case): self
 {
        $this->_state->join .= ' INNER JOIN `' . $this->_prefix . trim($table) . '` AS ' . $alias . ' ON ' . $case;
        return $this;
    }

    /**
  * @desc insert语句中的存在即更新, 注意! 数据表中必须存在主键或唯一索引
  * @access public
  * @return self
  */
 public function dupkeyUpdate($condition): self
 {
        if ($this->_state->query_type == 2) {
            if (is_array($condition)) {
                $clause = &$this->_state->on_duplicate_key_update;
                $values = &$this->_state->bind_params;
                foreach ($condition as $k => $v) {
                    $clause .= ',' . $k . '=?';
                    $values[] = $v;
                }
                $clause = ltrim($clause, ', ');
            } else {
                $this->_state->on_duplicate_key_update = $condition;
            }
            return $this;
        } else {
            $this->_trigger_exception('DUPLICATE KEY UPDATE: requires to start with INSERT at ' . __LINE__);
        }
    }

    /**
  * @desc where语句
  * @access public
  * @return self
  */
 public function where(): self
 {
        $this->_init_sqlstatement();

        $numOfArgs = func_num_args();

        if ($numOfArgs && is_array(func_get_arg(0))) {

            $clause = '';

            foreach (func_get_arg(0) as $k => $v) {

                $clause .= ' AND ' . $k . '=?';

                $this->_state->bind_params[] = $v;
            }
            if (empty($this->_state->where)) {
                $this->_state->where = ltrim($clause, ' AND ');
            } else {
                $this->_state->where .= ' AND ' . ltrim($clause, ' AND ');
            }
        } else {
            switch ($numOfArgs) {
                // 字符串条件
    case 1:
                    $clause = trim(func_get_arg(0));

                    if (empty($this->_state->where)) {
                        $this->_state->where = $clause;
                    } else {
                        $this->_state->where .= ' AND ' . $clause;
                    }

                    break;
                // 单等号条件
    case 2:
                    $clause = func_get_arg(0) . ' = ?';

                    if (empty($this->_state->where)) {
                        $this->_state->where = $clause;
                    } else {
                        $this->_state->where .= ' AND ' . $clause;
                    }
                    $this->_state->bind_params[] = func_get_arg(1);

                    break;
                // 其他符号条件
    case 3:
                    $arg1 = strtolower(func_get_arg(1));
                    if (array_key_exists($arg1, [
                        'in'  => 0,
                        'not in' => 0,
                    ])) {
                        if (trim(func_get_arg(2)) == '') {
                            $this->_trigger_exception('IN(): missing argument');
                        } else {
                            $clause = func_get_arg(0) . ' ' . $arg1 . ' (' . func_get_arg(2) . ')';
                            $this->_build_where_clause($clause);
                        }
                    } elseif (array_key_exists($arg1, [
                        'like'  => 0,
                        'not like' => 0
     ])) {
                        if (trim(func_get_arg(2)) == '') {
                            $this->_trigger_exception('LIKE(): missing argument at ' . __LINE__);
                        } else {
                            $clause = func_get_arg(0) . ' ' . $arg1 . " ('" . func_get_arg(2) . "')";
                            $this->_build_where_clause($clause);
                        }
                    } elseif (array_key_exists($arg1, [
                        '!=' => 0,
                        '>' => 0,
                        '>=' => 0,
                        '<=' => 0,
                        '<' => 0,
                        '<>' => 0,
                        '=' => 0,
                    ])) {
                        $clause = func_get_arg(0) . ' ' . $arg1 . ' ' . '?';

                        if (empty($this->_state->where)) {
                            $this->_state->where = $clause;
                        } else {
                            $this->_state->where .= ' AND ' . $clause;
                        }
                        $this->_state->bind_params[] = func_get_arg(2);
                    } else {
                        $this->_trigger_exception('where(): bad operator at ' . __LINE__);
                    }

                    break;
                // 过多的参数
    default:
                    $this->_trigger_exception('where(): too many arguments');
            }
        }
        return $this;
    }

    /**
  * @desc where 语句中的IN
  * @param string $field
  * @param array|string|int $values
  * @param string $param_type int或者string
  * @return self
  */
 public function whereIn($field, $values, $param_type = '', $method = 'IN')
    {
        if (is_string($values) || is_int($values)) {
            // 字符串
   $this->_build_where_clause(sprintf('%s %s (%s)', $field, $method, $values));
        }

        if (is_array($values)) {
            // 数组
   if (!count($values)) {
                $this->_trigger_exception($method . ': missing arguments');
            }

            $str = ltrim(array_reduce($values, function ($r, $vv) use ($param_type) {
                switch (gettype($vv)) {
                    case 'integer':
                        return sprintf('%s,%d', $r, $vv);
                    case 'string':
                        if ($param_type == 'int') {
                            return sprintf('%s,%d', $r, (int)$vv);
                        } else {
                            return sprintf("%s,'%s'", $r, addslashes($vv));
                        }
                    default:
                        $this->_trigger_exception('IN/NOT IN only supports int & string');
                }
            }), ',');

            $this->_build_where_clause(sprintf('%s %s (%s)', $field, $method, $str));
        }

        return $this;
    }
    
/**
 * @desc where 语句中的NOT IN处理
 * @param string $field
 * @param array|string $values
 * @return self
 */
public function whereNotIn($field, $values, $parameter_type = '')
{
    return $this->whereIn($field, $values, $parameter_type, 'NOT IN');
}

/**
 * @desc 在where语句的基础上增加或计算符的条件语句
 * @access public
 * @return self
 */
public function orWhere()
{
    switch (func_num_args()) {
        case 0:
            self::_trigger_runtime_exception('orWhere(): missing argument at ' . __LINE__);
        case 1:
            if (is_string(func_get_arg(0))) {
                if (empty($this->_state->where)) {
                    self::_trigger_runtime_exception('orWhere() must be called after other where() statements at ' . __LINE__);
                }
                // 字符串条件
    $this->_state->where .= ' OR ' . trim(func_get_arg(0));
            } else {
                self::_trigger_runtime_exception('orWhere(): type error at ' . __LINE__);
            }
            break;
        default:
            self::_trigger_runtime_exception('orWhere(): wrong behavior at ' . __LINE__);
    }

    return $this;
}

/**
 * @desc 组装where子句当中存在like或in方法时所用的代码复用方法
 * @access private
 * @param string $clause
 */
private function _build_where_clause(string $clause)
{
    if (empty($this->_state->where)) {
        $this->_state->where = $clause;
    } else {
        $this->_state->where .= ' AND ' . $clause;
    }
}

/**
 * @desc 连贯操作之排序
 * @access public
 * @param string $order
 * @return self
 */
public function orderBy(string $order): self
{
    $this->_state->order = ' ORDER BY ' . $order;
    return $this;
}

/**
 * @desc 连贯操作之分组
 * @access public
 * @param string $group
 * @return self
 */
public function groupBy(string $group): self
{
    $this->_state->group = ' GROUP BY ' . $group;
    return $this;
}

/**
 * @desc 连贯操作之having
 * @access public
 * @param string $having
 * @return self
 */
public function having(string $having): self
{
    $this->_state->having = ' HAVING ' . $having;
    return $this;
}

/**
 * @desc 批量更新方法
 * @access public
 * @param array $params 以主键为首个键值的数组
 * @return self
 */
public function batchUpdate($params): self
{
    $this->_state->query_type = 31;

    if (is_array($params) && isset($params[0])) {
        $primaryKey = $primaryValue = '';
        foreach ($params as $v) {
            foreach ($v as $k2 => $v2) {
                $primaryKey = $k2;
                $primaryValue = $v2;
                break;
            }
            break;
        }
        $arr2 = [];
        foreach ($params as $v) {
            $arr2[$v[$primaryKey]] = $v;
            array_splice($arr2[$v[$primaryKey]], $primaryKey, 1);
        }

        $sql = '';
        $sets = &$this->_state->bind_params;
        foreach ($arr2[$primaryValue] as $k => $v) {
            $sql .= sprintf('%s = CASE %s ', $k, $primaryKey);
            foreach ($arr2 as $k2 => $v2) {
                $sql .= "WHEN ? THEN ? ";
                $sets[] = $k2;
                $sets[] = $v2[$k];
            }
            $sql .= 'END, ';
        }

        $sql = substr($sql, 0, strrpos($sql, ','));

        $this->_state->update_field = $sql;

        $this->_state->where = sprintf('%s IN (%s)', $primaryKey, implode(',', array_keys($arr2)));
    } else {
        $this->_trigger_exception('batchUpdate(): bad parameter');
    }

    return $this;
}

/**
 * @desc 批量插入方法
 * @access public
 * @param array $params 二维数组 首个子数组内含键必须包含字段名称信息
 * @return self
 */
public function batchInsert($params): self
{
    $this->_state->query_type = 21;
    if (is_array($params) && count($params) >= 1) {
        $insertField = $insertValues = '';
        foreach ($params[0] as $k => $v) {
            $insertField .= sprintf(',`%s`', $k);
        }

        $this->_state->insert_field = ltrim($this->_state->insert_field, ',');

        foreach ($params as $v) {
            $insertValues .= '( ';
            foreach ($v as $vv) {
                $insertValues    .= ',?';
                $this->_state->bind_params[] = $vv;
            }
            $insertValues = sprintf('%s),', ltrim($insertValues, ','));
        }

        $this->_state->insert_values = ltrim($insertValues, ',');
    } else {
        $this->_trigger_exception('batchInsert(): bad parameter');
    }

    return $this;
}

/**
 * @desc 连贯操作之限制条数
 * @access public
 * @return self
 */
public function limit(): self
{
    switch (func_num_args()) {
        case 1:
            $this->_state->limit = sprintf('LIMIT %u', func_get_arg(0));
            break;
        case 2:
            $this->_state->limit = sprintf('LIMIT %u,%u', func_get_arg(0), func_get_arg(1));
            break;
        default:
            $this->_trigger_exception('limit(): bad parameter');
    }

    return $this;
}

/**
 * @desc 连贯操作之插入指定数据表
 * @access public
 * @param string $table
 * @return self
 */
public function insert(string $table): self
{
    $this->_init_sqlstatement();
    $this->_state->query_type = 2;

    $this->_state->table = $this->_prefix . trim($table);
    return $this;
}

/**
 * @desc 连贯操作之插入字段和对应值
 * @access public
 * @return self
 */
public function values(): self
{
    $numOfArgs = func_num_args();

    if ($numOfArgs) {
        $valuesArr = &$this->_state->bind_params;
        if (is_array(func_get_arg(0))) {
            $numOfValues = count(func_get_arg(0));
            $insertField = &$this->_state->insert_field;
            foreach (func_get_arg(0) as $k => $v) {
                $insertField .= ',`' . $k . '`';
                $valuesArr[] = $v;
            }
            $this->_state->insert_field = ltrim($this->_state->insert_field, ',');
        } else {
            $numOfValues = $numOfArgs;

            $this->_state->insert_field = '';
            for ($i = 0; $i < $numOfArgs; $i++) {
                $valuesArr[] = func_get_arg($i);
            }
        }

        $insertValues = &$this->_state->insert_values;

        $insertValues .= str_repeat(',?', $numOfValues);

        $insertValues = '( ' . ltrim($insertValues, ',') . ' )';
    } else {
        $this->_trigger_exception('values() expects at least 1 parameter');
    }
    return $this;
}

/**
 * @desc 连贯操作之获取插入的Id
 * @access public
 * @return self
 */
public function getId(): self
{
    $this->_state->get_last_inserted_id = 1;

    return $this;
}

// 获取指定字段的记录数量
public function count($field = '*')
{
    return $this->_callFuncOnFieldSelector('count', $field);
}

// 获取指定字段的最大值
public function max($field = '')
{
    return $this->_callFuncOnFieldSelector('max', $field);
}

// 获取指定字段的最小值
public function min($field = '')
{
    return $this->_callFuncOnFieldSelector('min', $field);
}

// 获取指定字段的平均值
public function avg($field = '')
{
    return $this->_callFuncOnFieldSelector('avg', $field);
}

// 获取指定字段的和
public function sum($field = '')
{
    return $this->_callFuncOnFieldSelector('sum', $field);
}

private function _callFuncOnFieldSelector($funcName, $field)
{
    $this->_state->query_type = 1;
    if (empty($field)) {
        $this->_trigger_exception('sql needs a field as parameter');
    } else {
        $this->_state->field = $funcName . '(' . $field . ')';
    }
    return $this->sql($this->_build_sql4query())->bind($this->_state->bind_params)->_grab();
}

/**
 * @desc 自增操作
 * @access public
 * @return self
 */
public function increase(): self
{
    switch (func_num_args()) {
        case 1:
            $this->_state->update_field = '`' . func_get_arg(0) . '` = `' . func_get_arg(0) . '`+1';
            break;
        case 2:
            $this->_state->update_field = '`' . func_get_arg(0) . '` = `' . func_get_arg(0) . '`+?';

            $this->_state->bind_params[] = func_get_arg(1);
            break;
        default:
            $this->_trigger_exception('invalid parameter while using increment()');
    }

    return $this;
}

/**
 * @desc 自减操作
 * @access public
 * @return self
 */
public function decrease(): self
{
    switch (func_num_args()) {
        case 1:
            $this->_state->update_field = '`' . func_get_arg(0) . '` = `' . func_get_arg(0) . '`-1';
            break;
        case 2:
            $this->_state->update_field = '`' . func_get_arg(0) . '` = `' . func_get_arg(0) . '`-?';

            $this->_state->bind_params[] = func_get_arg(1);
            break;
        default:
            $this->_trigger_exception('invalid paramter while using decrement()');
    }

    return $this;
}

/**
 * @desc 连贯操作之开始插入数据
 * @access public
 * @return array|false|mixed|void
 */
public function go()
{
    if ($this->_state->is_sql_native) {

        // 原生语句执行
  if ($this->_state->query_type == 1) {
            $this->_trigger_exception('sql query type error at ' . __LINE__);
        }
    }

    switch ($this->_state->query_type) {
        case 2: // 插入
  case 21:
            return $this->_run($this->_build_sql4insert(), $this->_state->bind_params, 4);
        case 3: // 更新
  case 31:
            return $this->_run($this->_build_sql4update(), $this->_state->bind_params, 5);
        case 4: // 删除
   return $this->_run($this->_build_sql4delete(), $this->_state->bind_params, 6);
        default:
            $this->_trigger_exception('can not determine sql type.');
    }
}

/**
 * @desc 连贯操作之更新的目标数据表
 * @access public
 * @param string $table
 * @return self
 */
public function update(string $table): self
{
    $this->_init_sqlstatement();
    $this->_state->query_type = 3;

    $this->_state->table = $this->_prefix . trim($table);

    return $this;
}

/**
 * @desc 连贯操作之指定更新的字段和值
 * @access public
 * @param array $params
 * @return self
 */
public function set(array $params): self
{
    $updateField = &$this->_state->update_field;
    $setsArr  = &$this->_state->bind_params;
    foreach ($params as $k => $v) {
        $updateField .= ',`' . $k . '`=?';
        $setsArr[]   = $v;
    }
    $updateField = ltrim($updateField, ',');
    return $this;
}

/**
 * @desc 连贯操作之删除的目标数据库
 * @access public
 * @param string $table
 * @return self
 */
public function delete(string $table): self
{
    $this->_init_sqlstatement();
    $this->_state->query_type = 4;

    $this->_state->table = $this->_prefix . trim($table);

    return $this;
}

/**
 * 查询多行
 * @access public
 */
public function all()
{
    if ($this->_state->is_sql_native) {
        // 原生语句
  return $this->_all();
    } else {
        // 连贯操作
  if (func_num_args() && func_get_arg(0) > 0) {
            $this->_state->limit = ' LIMIT ' . abs((int)func_get_arg(0));
        }

        return $this->sql($this->_build_sql4query())->bind($this->_state->bind_params)->_all();
    }
}

/**
 * 方法别名: 查询多行
 * @access public
 */
public function rows()
{
    return $this->all();
}

/**
 * 查询单行
 * @access public
 * @return array
 */
public function fetch()
{
    if ($this->_state->is_sql_native) {
        // 原生语句
  return $this->_fetch();
    } else {
        // 连贯操作
  $this->_state->limit = ' LIMIT 1';

        return $this->sql($this->_build_sql4query())->bind($this->_state->bind_params)->_fetch();
    }
}

public function row()
{
    return $this->fetch();
}

/**
 * 函数别名: 查询一行, 兼容TP框架orm
 * @access public
 */
public function find()
{
    return $this->row();
}

/**
 * 查询一个
 */
public function grab()
{
    if ($this->_state->is_sql_native) {
        // 原生语句
  return $this->_grab();
    } else {
        // 连贯操作
  $this->_state->limit = ' LIMIT 1';
        if (func_num_args() && !empty(func_get_arg(0))) {
            $this->_state->field = trim(func_get_arg(0));
        }
        return $this->sql($this->_build_sql4query())->bind($this->_state->bind_params)->_grab();
    }
}

/**
 * 打印出Sql语句
 * @access public
 * @return bool|string|void
 */
public function getSql()
{
    switch ($this->_state->query_type) {
        case 1:
            return $this->_build_sql4query();
        case 2:
        case 21:
            return $this->_build_sql4insert();
        case 3:
        case 31:
            return $this->_build_sql4update();
        case 4:
            return $this->_build_sql4delete();
        default:
            $this->_trigger_exception('unknown sql type');
    }
}

/**
 * 方法别名: 打印sql语句
 * @access public
 */
public function print()
{
    return $this->getSql();
}

/**
 * 方法别名: 打印Sql语句
 * @access public
 */
public function dump()
{
    return $this->getSql();
}

/**
 * 构造删除用的Sql语句
 * @access private
 */
private function _build_sql4delete()
{
    // 如果where条件不存在,则终止操作
 if (empty($this->_state->table) || empty($this->_state->where)) {
        return false;
    }

    $this->_state->sql_statement = 'DELETE FROM `' . $this->_state->table . '` WHERE ' . $this->_state->where . $this->_state->limit;

    return $this->_state->sql_statement;
}

/**
 * 构造更新用的Sql语句
 * @access private
 * @return string
 */
private function _build_sql4update()
{
    // 如果where条件不存在,则终止操作
 if (empty($this->_state->table) || empty($this->_state->where)) {
        self::_trigger_runtime_exception('Attempted unconditionally update. Stop.');
    }

    $this->_state->sql_statement = 'UPDATE `' . $this->_state->table . '` SET ' . $this->_state->update_field . ' WHERE ' . $this->_state->where . $this->_state->limit;

    return $this->_state->sql_statement;
}

 /**
  * 构造插入用的Sql语句
  * @access private
  */
 private function _build_sql4insert()
    {
        if (empty($this->_state->table)) {
            return false;
        }

        if (empty($this->_state->insert_field)) {
            $this->_state->sql_statement = empty($this->_state->on_duplicate_key_update) ? 'INSERT INTO `' . $this->_state->table . '` VALUES ' . $this->_state->insert_values : 'INSERT INTO `' . $this->_state->table . '` VALUES ' . $this->_state->insert_values . ' ON DUPLICATE KEY UPDATE ' . $this->_state->on_duplicate_key_update;
        } else {
            $this->_state->sql_statement = empty($this->_state->on_duplicate_key_update) ? 'INSERT INTO `' . $this->_state->table . '` ( ' . $this->_state->insert_field . ' ) VALUES ' . $this->_state->insert_values : 'INSERT INTO `' . $this->_state->table . '` ( ' . $this->_state->insert_field . ' ) VALUES ' . $this->_state->insert_values . ' ON DUPLICATE KEY UPDATE ' . $this->_state->on_duplicate_key_update;
        }

        return $this->_state->sql_statement;
    }

    /**
  * 构造查询用的Sql语句
  * @access private
  * @return string
  */
 private function _build_sql4query()
    {
        if (empty($this->_state->table)) {
            self::_trigger_runtime_exception('No table was specified while querying');
        }

        $this->_state->sql_statement = sprintf('SELECT %s FROM %s %s %s %s %s %s %s', $this->_state->field, $this->_state->table, $this->_state->join, empty($this->_state->where) ? '' : 'WHERE ' . $this->_state->where, $this->_state->group, $this->_state->having, $this->_state->order, $this->_state->limit);

        return $this->_state->sql_statement;
    }

    /**
  * 触发错误并销毁sql状态存储对象
  * @access public
  * @param string $msg
  */
 private function _trigger_exception(string $msg)
    {
        $this->_state = null;

        throw new \PDOException($msg);
    }

    /**
  * 准备Sql语句
  * @access public
  * @param string $sql 原始sql语句
  * @return self
  */
 public function sql(string $sql): self
 {
        $this->_init_sqlstatement();

        $this->_state->is_sql_native = 1;

        if (trim($sql) == '') {
            $this->_trigger_exception('no sql found');
        } else {
            switch (strtolower($sql[0])) {
                case 's':
                    // select 查询语句
     $this->_state->query_type = 1;
                    break;
                case 'i':
                    // insert 插入语句
     $this->_state->query_type = 2;
                    break;
                case 'u':
                    // update 更新语句
     $this->_state->query_type = 3;
                    break;
                case 'd':
                    if (strtolower($sql[1]) == 'e') {

                        // delete 删除语句
      $this->_state->query_type = 4;
                        break;
                    } else {
                        // 不支持风险语句drop
      $this->_trigger_exception('operation type error');
                    }
                default:
                    $this->_trigger_exception('operation type error');
            }

            $this->_state->sql_statement = str_ireplace('*_', $this->_prefix, trim($sql));
        }

        return $this;
    }

    /**
  * 准备绑定的参数
  * @access public
  */
 public function bind($params): self
 {
        $this->_state->bind_params = $params;
        return $this;
    }

    /**
  * 使用cache存储
  * @param int $ttl 生存秒
  * @param string $key
  */
 public function cache(int $ttl = 30, string $key = '')
    {
        $this->_state->cache = 1;

        $this->_state->cache_ttl = abs((int)$ttl);
        $this->_state->cache_key = $key;

        return $this;
    }

    /**
  * @desc 参数绑定处理
  * @access private
  * @param object $pdo_statement
  * @param array $params
  * @return object
  */
 private static function preparation_loop($pdo_statement, $params)
    {
        foreach ($params as $k => $v) {
            switch (gettype($v)) {
                case 'integer':
                case 'double':
                    $pdo_statement->bindValue($k + 1, $v, \PDO::PARAM_INT);
                    break;
                case 'string':
                    $pdo_statement->bindValue($k + 1, $v, \PDO::PARAM_STR);
                    break;
                case 'boolean':
                    $pdo_statement->bindValue($k + 1, ($v ? '1' : '0'), \PDO::PARAM_BOOL);
                    break;
                case 'NULL':
                    $pdo_statement->bindValue($k + 1, null, \PDO::PARAM_NULL);
                    break;
                case 'resource':
                    $pdo_statement->bindValue($k + 1, $v, \PDO::PARAM_LOB);
                    break;
                case 'array':
                    self::_trigger_runtime_exception('An array with > 2 dimensions was passed into the where clause');
            }
        }

        return $pdo_statement;
    }

    /**
  * 预编译执行SQL
  * @access private
  * @param string $sql 带有占位符的sql语句
  * @param array $params 绑定的参数
  * @param int $sql_type 执行类型 1 多行 2 单行 3 单个 4 插入 5 更新
  * @return mixed    查询结果,或执行后受影响的行数
  * @author qinchao <castor@happycoworker.com>
  */
 private function _run($sql, $params = [], $sql_type = 1)
    {

        if ($params === []) {
            $pdo_statement = $this->_mysql_handler->pdo_instance->query($sql);
        } else if (empty($sql)) {
            $this->_trigger_exception('No sql.');
        } else {
            $pdo_statement = $this->_mysql_handler->pdo_instance->prepare($sql);
        }

        if ($this->_mysql_handler->pdo_instance->errorCode() != '00000') {
            $errInfo = $this->_mysql_handler->pdo_instance->errorInfo();
            if ($errInfo[1] === 2013 || $errInfo[1] === 2016 || is_string($errInfo[2]) && strpos($errInfo[2], 'STMT_PREPARE') !== false) {
                // 此时已断线
    $this->_reconnect();
                return $this->_run($sql, $params, $sql_type);
            } else {
                // 其他错误
    if ($this->_log == 1) {

                    error_log(@json_encode(array_merge($this->_mysql_handler->pdo_instance->errorInfo(), [$sql]), JSON_PRETTY_PRINT), 3, SWOOLE_LOG_FILE);
                }

                $this->_trigger_exception(json_encode($this->_mysql_handler->pdo_instance->errorInfo(), JSON_UNESCAPED_UNICODE));
            }
        }

        if ($pdo_statement === false) {
            $this->_state = null;
            return false;
        }

        if ($params !== []) {
            if (is_array($params)) {

                $pdo_statement = self::preparation_loop($pdo_statement, $params);

                $pdo_statement->execute($params);
            } else {
                $pdo_statement = self::preparation_loop($pdo_statement, [$params]);

                $pdo_statement->execute();
            }
        }

        switch ($sql_type) {
            case 1:
                $r = $pdo_statement->fetchAll(\PDO::FETCH_ASSOC);
                if ($r === false) {
                    $r = [];
                }
                break;
            case 2:
                $r = $pdo_statement->fetch(\PDO::FETCH_ASSOC);
                if ($r === false) {
                    $r = [];
                }
                break;
            case 3:
                $r = $pdo_statement->fetchColumn();
                break;
            case 4: // 插入
    $r = $pdo_statement->rowCount();
                if ($r && $this->_state->get_last_inserted_id == 1) {
                    $r = $this->_mysql_handler->pdo_instance->lastInsertId();
                }

                $pdo_statement = null;
                $this->_state = null;
                return $r;
            case 5: // 更新
   case 6: // 删除
    $r   = $pdo_statement->rowCount();
                $pdo_statement = null;
                $this->_state = null;
                return $r;

            default:
                self::_trigger_runtime_exception("Illegal query type.");
        }

        if ($this->_state->cache == 1) {
            $this->_writeInRedis($r);
        }

        $pdo_statement = null;
        $this->_state = null;

        return $r;
    }

    /**
  * 往缓存里写数据
  * @access private
  */
 private function _writeInRedis($data)
    {
        $r = RedisWorker::connect($this->_redis_config['db']);

        if (trim((string)$this->_state->cache_key) == '') {

            $this->_state->cache_key = substr(md5($this->_state->sql_statement . json_encode($this->_state->bind_params)), 4, 24);
        }
        if (!$r->exists($this->_state->cache_key)) {
            $r->set($this->_state->cache_key, (string)json_encode($data));
            $r->expire($this->_state->cache_key, $this->_state->cache_ttl);
        }
        $r->close();
    }

    /**
  * 从缓存取数据
  * @access private
  */
 private function _read_from_redis($sql_type)
    {
        $r = RedisWorker::connect($this->_redis_config['db']);

        if (trim((string)$this->_state->cache_key) == '') {
            $result = $r->get(substr(md5($this->_state->sql_statement . (count($this->_state->bind_params) > 0 ? json_encode($this->_state->bind_params) : '')), 4, 24));
            if (!$result) {
                $r->close();
                return $this->_run($this->_state->sql_statement, $this->_state->bind_params, $sql_type);
            } else {
                $this->_state = null;
                $r->close();
                return json_decode($result, true);
            }
        } else {
            $result = $r->get($this->_state->cache_key);
            if (!$result) {
                // 结果已过期
    $r->close();
                return $this->_run($this->_state->sql_statement, $this->_state->bind_params, $sql_type);
            } else {
                $this->_state = null;
                $r->close();
                return json_decode($result, true);
            }
        }
    }

    // 预编译方式读取多行
 private function _all()
    {
        if (trim($this->_state->sql_statement) == '') {
            $this->_trigger_exception('No sql');
        } else {
            if ($this->_state->cache == 1) {
                $result = $this->_read_from_redis(1);
            } else {
                $result = $this->_run($this->_state->sql_statement, $this->_state->bind_params, 1);
            }

            return $result;
        }
    }

    /**
  * 预编译方式获取1行
  * @return array|false
  */
 private function _fetch()
    {
        if (trim($this->_state->sql_statement) == '') {
            $this->_trigger_exception('No sql');
        } else {
            if ($this->_state->cache == 1) {
                $result = $this->_read_from_redis(2);
            } else {
                $result = $this->_run($this->_state->sql_statement, $this->_state->bind_params, 2);
            }

            return $result;
        }
    }

    /**
  * 预编译方式读取1个
  * @access private
  */
 private function _grab()
    {
        if (trim($this->_state->sql_statement) == '') {
            $this->_trigger_exception('No sql');
        } else {
            if ($this->_state->cache == 1) {
                $result = $this->_read_from_redis(3);
            } else {
                $result = $this->_run($this->_state->sql_statement, $this->_state->bind_params, 3);
            }

            return $result;
        }
    }

    /**
  * @desc 呼叫匿名方法
  * @access public
  * @param $fn
  * @param $args
  * @return Worker|void
  */
 public function __call($fn, $args)
    {
        switch (count($args)) {
            case 1: // where+字段名
    $this->_init_sqlstatement();

                if (strtolower(substr($fn, 0, 5)) == 'where') {
                    $field = strtolower(substr($fn, 5));

                    if (empty($this->_state->where)) {
                        $this->_state->where = $field . ' = ?';
                    } else {
                        $this->_state->where .= ' AND ' . $field . ' = ?';
                    }

                    $this->_state->bind_params[] = $args[0];
                }

                return $this;
        }
    }

    /**
  * @desc 触发错误并销毁sql状态存储对象
  * @access private
  * @param string $msg
  */
 private static function _trigger_runtime_exception(string $msg)
    {
        throw new \Exception($msg);
    }

    /**
  * 关闭连接
  * @access public
  * @return void
  */
 public function close()
    {
        $this->_mysql_handler->close();
    }

    /**
  * 析构
  * @access public
  */
 public function __destruct()
    {
        $this->_mysql_handler->close();
    }
}

注意: 这些代码是阻塞的, 不适用于协程版的swoole。

阅完此文,您的感想如何?
  • 有用

    0

  • 没用

    0

  • 开心

    0

  • 愤怒

    0

  • 可怜

    0

1.如文章侵犯了您的版权,请发邮件通知本站,该文章将在24小时内删除;
2.本站标注原创的文章,转发时烦请注明来源;
3.交流群: PHP+JS聊天群

相关课文
  • mac开发接入微信公众号接口返回报错 cURL error 56: SSLRead() return error -9806

  • pecl安装程序时报错Array and string offset access syntax with curly braces is no longer supported

  • PHP的换行符是什么

  • 由于商家传入的H5交易参数有误,该笔交易暂时无法完成,请联系商家解决

我要说说
网上宾友点评
1 楼 IP 61.150.12.198 的嘉宾 说道 : 1578298472
你好,我们测试一下