1

我编写了一个 mini-DBAL,这是其中的一部分。

private function setWhere($conditions) {
    if (count($conditions)>0) {
        $where = '1=1';
        $params = [];

        $ret = $this->iterateWhere($where, $conditions, $params, 'AND', '=');
        return [
                    'where' => 'WHERE '.str_replace('1=1 OR ', '', str_replace('1=1 AND ', '', $ret['where'])),
                    'params' => $ret['params'],
                ];
    } else
        return [
                    'where' => '',
                    'params' => [],
                ];
}

private function iterateWhere($where, $conditions, $params, $logic, $op) {
    //go through given set of conditions
    foreach ($conditions as $condition=>$value) {
        //check for lowest condition
        if (is_array($value)) {
            //check for logic or operator condition
            if (in_array($value[0], ['AND', 'OR', 'and', 'or'])) {
                //logic
                $where .= ' '.$logic.' (1=1';
                $ret = $this->iterateWhere($where, $value, $params, $value[0], $op);
                $where = $ret['where'];
                $params = $ret['params'];
                $where .= ')';
            } else {
                //operator
                foreach($value as $k=>$v) {
                    if ($k != '0') {
                        $where .= ' '.$logic.' ('.$k.$value[0].':'.count($params).')';
                        $params[] = $v;
                        break;
                    }
                }
            }
        } else {
            if ($condition != '0') {
                $where .= ' '.$logic.' ('.$condition.$op.':'.count($params).')';
                $params[] = $value;
            } else {
                if (in_array($value, ['AND', 'OR', 'and', 'or']))
                    $logic = strtoupper($value);
                else
                    $op = strtoupper($value);
            }
        }
    }

    return [
                'where' => $where,
                'params' => $params,
            ];
}

public function getTableCol($table, $column, $conditions) {
    try {
        $condition_part = $this->setWhere($conditions);
        $stmt = $this->pdo->prepare('SELECT '.$column.' FROM '.$table.' '.$condition_part['where']);

        foreach ($condition_part['params'] as $param=>$pVal) {
            switch (strtolower(gettype($pVal))) {
                case 'string':
                    $stmt->bindParam(':'.$param, $pVal, \PDO::PARAM_STR);
                    break;

                case 'integer':
                    $stmt->bindParam(':'.$param, $pVal, \PDO::PARAM_INT);
                    break;

                case 'float':
                case 'double':
                    $stmt->bindParam(':'.$param, $pVal);
                    break;

                case 'boolean':
                    $stmt->bindParam(':'.$param, $pVal, \PDO::PARAM_BOOL);
                    break;

                case 'null':
                    $stmt->bindParam(':'.$param, $pVal, \PDO::PARAM_NULL);
                    break;

                default:
                    die('Unhandled param type for \''.$pVal.'\'');
                    break;
            }
        }

        $stmt->execute();
        $ret = $stmt->fetchAll(\PDO::FETCH_COLUMN, 0);

        return [
                    'rows' => count($ret),
                    'result' => $ret,
                ];
    } catch (\PDOException $e) {
        return [
                    'rows' => 0,
                    'result' => $e->getMessage(),
                ];
    }
}

我这样称呼我的函数:

$client_list = $db->getTableCol("cs_client", "client_id", ["domain" => "PB", "name" => "My Client"]);

我发现我的代码正确地填充了 SQL 和参数,但是当我传递多个 WHERE 条件时它不会返回任何行。如果我手动对动态准备的语句进行硬编码,那么它就可以工作。我不知道为什么。

以下是 echo 和 print_r 的一些输出:

SQL 传递到 prepare():

SELECT client_id FROM cs_client WHERE (domain=:0) AND (name=:1)

参数的数组输出:

Array
(
    [0] => PB
    [1] => My Client
)

for 循环中的序列以绑定参数:

0 => PB
1 => My Client

要重新迭代,如果我将准备好的语句手动复制粘贴到 '$stmt = $this->pdo->prepare("")' 然后使用输出值绑定 :0 和 :1 ,它将返回唯一的行在那张桌子上。

如果我只通过一个(两个条件之一)或没有条件,那么它返回该行,但如果我通过两个条件则不返回,尽管它填充了正确的条件。

没关系,但我使用的是 MS SQL Server 2014。

4

1 回答 1

0

我想我是太努力了。而不是使用 count() 将命名参数递增为 0、1、2、3... 我只是使用了 '?' 并将参数列表传递给执行语句,如下所示:

$stmt->execute($condition_part['params']);

生成更小的代码,因为我不需要循环来遍历参数列表。

于 2017-02-05T20:26:31.480 回答