封装sql链式操作

前言

用习惯了tp这种链式操作框架,因为项目原因不能使用tp这种框架,只能自己手动拼接sql,这种对于不愿用点号一直拼的人很是恼火,于是本人封装了一个简单的链式操作,来获取sql,然后用pdo直接执行sql语句获取结果。

代码说明

里面运用的基本是面向对象的思想,用到了一个PHP不算常用的场景,反射,大大的节省了代码量。自己亲手封装,仅供参考,代码中没有对于注入进行处理,需要的小伙伴可以自己进行二次改进。

class DbSql
{
    //属性声明顺序不可变化,否则影响sql语句中关键字的顺序
    private $table;//表名
    public $child;//子查询
    private $join;//连接
    private $where;//条件
    private $between;//between and
    private $group;//分组
    private $having;//分组后操作
    private $order;//排序
    private $field;//字段,默认为*
    private $limit;//限制
    //使用call
    public function __call($name, $arg)
    {
        if ($name == 'where') {
            $this->$name[] = $arg[0];
        } elseif ($name == 'join') {
            $this->$name[] = $arg;
        } else {
            $this->$name = $arg[0];
        }
        return $this;
    }
    //最终生成sql语句
    public function sql()
    {
        $ref = new ReflectionClass($this);
        $sql = '';
        //方法名称映射
        $map = [
            'order' => ' order by ',
            'group' => ' group by ',
            'table' => ' select ',
            'child' => ' select ',
        ];
        foreach ($ref->getProperties() as $pro) {
            $pro_name = $pro->name;//属性名称
            $this_attr = $this->$pro_name;//对应的属性具体值
            if (!empty($this_attr)) {
                $arr = [isset($map[$pro_name]) ? $map[$pro_name] : $pro_name];//初始化行为
                if ($pro_name == 'table') {
                    $arr = array_merge($arr, [$this->field == '' ? '*' : $this->field, 'from', $this->table]);
                } elseif ($pro_name == 'child') {
                    $child_sql = substr($this_attr, 0, strripos($this_attr, ' '));
                    $alias = substr($this_attr, strripos($this_attr, ' '));
                    $arr = array_merge($arr, [$this->field == '' ? '*' : $this->field], ['from ( ', $child_sql, ' ) ', $alias]);
                } elseif ($pro_name == 'join') {
                    $arr = [$this->buildJoin()];
                } elseif ($pro_name == 'where') {
                    $arr[] = rtrim($this->buildWhere(), ' and');
                } elseif ($pro_name == 'between') {
                    $between = explode(',', $this_attr);
                    $arr = [' and ' . $between[0], 'between', $between[1] . ',', $between[2]];
                } else {
                    $arr[] = $this_attr;
                }
                $this->$pro_name = null;
                $sql .= ' ' . implode(' ', $arr);
            }
        }
        return $sql;
    }

    //处理where条件
    private function buildWhere()
    {
        $sql = "";
        if (is_array($this->where)) {
            foreach ($this->where as $k => $v) {
                //关联数组
                if ($this->array_depth($v) == 1) {
                    foreach ($v as $kk => $vv) {
                        //纯字符串
                        if (is_numeric($kk)) {
                            $sql .= "'{$vv}' and ";
                        } else {
                            $sql .= "$kk = '{$vv}' and ";
                        }
                    }
                } elseif ($this->array_depth($v) == 2) {
                    foreach ($v as $kkk => $vvv) {
                        if (is_array($vvv)) {
                            $sql .= " $kkk {$vvv[0]} '{$vvv[1]}' and ";
                        }
                    }
                }
            }
        }
        return $sql;
    }

    //处理join条件
    private function buildJoin()
    {
        $sql = "";
        if (is_array($this->join)) {
            foreach ($this->join as $k => $v) {
                if (!isset($v[2])) {
                    $joinType = ' inner join ';
                } else {
                    $joinType = $v[2] . ' join ';
                }
                $sql .= $joinType . $v[0] . ' on ' . $v[1] . ' ';
            }
        }
        return $sql;
    }

    //获取数组维度主要用于判断where
    function array_depth($array)
    {
        if (!is_array($array)) return 0;
        $max_depth = 1;
        foreach ($array as $value) {
            if (is_array($value)) {
                $depth = $this->array_depth($value) + 1;
                if ($depth > $max_depth) {
                    $max_depth = $depth;
                }
            }
        }
        return $max_depth;
    }
}

运行实例

$where = [];
$where['name'] = ['like', '%1111%'];
$db = new DbSql();
$sql = $db->table('a')
    ->where(['id' => 1])
    ->where($where)
    ->between('ass,1,2')
    ->order('id desc')
    ->group('a.id')
    ->join('user u', 'a.id=o.id', 'left')
    ->join('user11 u1', 'a1.id=o1.id', 'left')
    ->limit('1,2')
    ->sql();

打印$sql
select * from a left join user u on a.id=o.id left join user11 u1 on a1.id=o1.id where id = '1' and name like '%1111%' and ass between 1, 2 group by a.id order by id desc limit 1,2
在用Think.PHP的时候, 发现它的数据库操作非常简单. 直接类似这样的写法就可以了. 于是决定用易语言模仿一个, 这个版本只支持 "生拼装SQL", 下次准备结合ad0o对象. 允许直接操作数据库 制作这么一个东西的初衷是为了 "更快更高效的开发程序", 我们往往在SQL上耽搁了太多时间. 并不是它难. 而是难以维护 难以修改. [子文本替换拼装], [字符串拼装].... 这些都用过. 一旦比较长的sql 改懂就比较麻烦 这个类喜欢你能喜欢. ------------------------------------------------------ 这个模块是用之前我写的简单键值对, 是用 数组+自定义数据类型 弄的. 可以替换掉 其实我早就想换了. 相对以前的版本 [增加] Coun t() [增加] To p() [修复] pag e() 分页出现负数 [更新] 抛弃用"类自身" 克0隆, 怕有什么问题.  改用特定方法设置内容 [更新] 简单键值对 2016-12-30: 连夜更新了模块,  已经可以绑定ado对象.   直接操作数据库. 实现几乎完全一样的操作, 除不是若类型语言, 对数据类型的苛刻要求.  无法直接返回数据.   其他基本上差不多了 这个版本暂时不开源, 想体验的朋友可以加群  178569305 2016-12-30: [废除] 简单键值对, 改 "自定义数据类型->数组" [废除] 生组装SQL [革命] 增加 "绑定adodb连接件对象", "绑定adodb记录集对象" [革命] 增加 "调试模式"  用于快速定位错误 [增加] 增加 读写模式,  "插入", "更新", "读取" 用重复的代码, 改下读写模式就OK~ [革命] 改 "SqlModel" 为 "DbModel" [废除] val_Single  小数型 (可以直接用Val_double 双精度替代) [废除] val_All 自定义内容,  可以用在  DbModel->data("字段名", "我是内容")  参数2 替代 [增加] RecordCount (取记录数),  FieldCount (取字段数)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

壬戌知秋

您的打赏将是我最大的鼓励感谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值