PHP,使用对象构建SQL语句是一种不好的做法吗?

时间:2015-04-09 15:29:14

标签: php oop

使用对象构建SQL语句是否过度杀伤?

是否为SQL语句定义了足够的字符串?

这是我的PHP和SQL代码:

class SQLStatement  {
private $table;
    private $sql;

    const INNER_JOIN = 'INNER JOIN';
    const LEFT_JOIN = 'LEFT JOIN';
    const RIGHT_JOIN = 'RIGHT JOIN';
    const OUTER_JOIN = 'OUTER JOIN';

    public function __construct($table) {
        $this->setTable($table);
    }

    public function setTable($table) {
        $this->table = $table;
    }

    public function buildFromString($string) {
        $this->sql = $sql;
    }

    public function select(array $columns) {
        $sql = 'SELECT ';
        $columns = implode(',', $columns);
        $sql .= $columns;
        $sql .= " FROM $this->table";

        $this->sql = $sql;
        return $this;
    }

    /**
     * Setting up INSERT sql statement
     *
     * @param array $records The records to insert.The array keys must be the columns, and the array values must be the new values
     * @return object Return this object back for method chaining
     */
    public function insert(array $records) {
        $columns = array_keys($records);
        $values = array_values($records);
        $values = array_map('quote',$values);
        $sql = 'INSERT INTO ';
        $sql .= $this->table . '('. implode(',', $columns) . ')';
        $sql .= ' VALUES ' . '(' . implode(',', $values) . ')';

        $this->sql = $sql;
        return $this;
    }

    /**
     * Setting up UPDATE sql statement
     *
     * @param array $records The records to update. The array keys must be the columns, and the array values must be the new records
     * @return object Return this object back for method chaining
     */
    public function update(array $records, $where) {
        $sql = 'UPDATE ' . $this->table . ' SET ';
        $data = array();
        foreach ($records as $column => $record) {
            $data[] = $column . '=' . quote($record);
        }
        $sql .= implode(', ', $data);
        $this->sql = $sql;
        return $this;
    }

    /**
     * Setting up DELETE sql statement
     * @return object Return this object back for method chaining
     */
    public function delete($where=null) {
        $sql = 'DELETE FROM ' . $this->table;
        $this->sql = $sql;
        if (isset($where)) {
            $this->where($where);
        }
        return $this;
    }

    /**
     * Setting up WHERE clause with equality condition. (Currently only support AND logic)
     * @param  array  $equalityExpression Conditional equality expression. The key is the column, while the value is the conditional values
     * @return object                     Return this object back for method chaining
     * 
     */ 
    public function where(array $equalityExpression) {
        if (!isset($this->sql)) {
            throw new BadMethodCallException('You must use SELECT, INSERT, UPDATE, or DELETE first before where clause');
        }
        $where = ' WHERE ';
        $conditions = array();
        foreach ($equalityExpression as $column => $value) {
            if (is_array($value)) {
                $value = array_map('quote', $value);
                $conditions[] = "$column IN (" . implode(',', $value) . ')';
            }
            else {
                $value = quote($value);
                $conditions[] = "$column = $value";
            }
        }
        $where .= implode(' AND ', $conditions);
        $this->sql .= $where;
        return $this;
    }

    /**
     * Setting up WHERE clause with expression (Currently only support AND logic)
     * @param  array  $expression Conditional expression. The key is the operator, the value is array with key being the column and the value being the conditional value
     * @return object             Return this object back for method chaining
     */
    public function advancedWhere(array $expression) {
        if (!isset($this->sql)) {
            throw new BadMethodCallException('You must use SELECT, INSERT, UPDATE, or DELETE first before where clause');
        }
        if (!is_array(reset($expression))) {
            throw new InvalidArgumentException('Invalid format of expression');
        }
        $where = ' WHERE ';
        $conditions = array();
        foreach ($expression as $operator => $record) {
            foreach ($record as $column => $value) {
                $conditions[] = $column . ' ' . $operator . ' ' . quote($value);
            }
        }
        $where .= implode(' AND ', $conditions);
        $this->sql .= $where;
        return $this;
    }

    /**
     * Setting up join clause (INNER JOIN, LEFT JOIN, RIGHT JOIN, or OUTER JOIN)
     * @param  array  $tables <p>Tables to join as the key and the conditions array as the value (Currently only support ON logic)</p>
     *                        <p>Array example : array('post'=>array('postid'=>'post.id'))</p>
     * @param  string $mode   The mode of join. It can be INNER JOIN, LEFT JOIN, RIGHT JOIN, or OUTER JOIN
     * @return object         Return this object back for method chaining
     */
    public function join(array $joins, $mode = self::INNER_JOIN) {
        if (!isset($this->sql) && strpos($this->sql, 'SELECT')) {
            throw new BadMethodCallException('You must have SELECT clause before joining another table');
        }
        if (!is_array(reset($joins))) {
            throw new InvalidArgumentException('Invalid format of the join array.');
        }
        $Conditions = array();
        foreach ($joins as $table => $conditions) {
            $join = ' ' . $mode . ' ' . $table . ' ON ';
            foreach ($conditions as $tbl1 => $tbl2) {
                $Conditions[] = $tbl1 .  ' = ' . $tbl2;
            }
            $join .= implode(' AND ', $Conditions);
        }
        $this->sql .= $join;
        return $this;
    }

    /**
     * Setting up GROUP BY clause
     * @param  array  $columns The columns you want to group by
     * @param  string $sort    The type of sort, ascending is the default
     * @return object          Return this object back for method chaining
     */
    public function groupBy(array $columns, $sort = 'ASC') {
        if (!isset($this->sql)) {
            throw new BadMethodCallException('You must use SELECT, INSERT, UPDATE, or DELETE first before group by clause');
        }
        $groupBy = ' GROUP BY ' . implode(',', $columns) . ' ' . $sort;
        $this->sql .= $groupBy;
        return $this;
    }

    /**
     * Setting up HAVING clause with expression
     * @param  expression  $expression Conditional expression. The key is the operator, the value is an array with key being the column and the value being the conditional value
     * @return object             Return this object back for method chaining
     */
    public function having($expression) {
        if (!isset($this->sql) && strpos($this->sql, 'GROUP BY') === FALSE) {
            throw new BadMethodCallException('You must have SELECT, INSERT, UPDATE, or DELETE and have GROUP BY clause first before where clause');
        }
        if (!is_array(reset($expression))) {
            throw new InvalidArgumentException('Invalid format of expression');
        }
        $having = ' HAVING ';
        $conditions = array();
        foreach ($expression as $operator => $record) {
            foreach ($record as $column => $value) {
                $conditions[] = $column . ' ' . $operator . ' ' . $value;
            }
        }
        $having .= implode(' AND ', $conditions);
        $this->sql .= $having;
        return $this;
    }

    /**
     * Return the SQL statement if this object is supposed to be string
     * @return string The sql statement
     */
    public function __toString() {
        return $this->sql;
    }
}

我发现的缺点是当我需要使用预准备语句时,因为预处理语句包含占位符。

我应该在我的SQL语句对象中添加一个功能来执行预准备语句吗?什么时候应该使用准备好的陈述好的做法?

1 个答案:

答案 0 :(得分:3)

使用对象或准备好的陈述并不过分或过度使用,这些都是很好的做法。

目标是制作多功能且可重复使用的东西,看起来你正走在正确的轨道上。

但是,很多人已经这样做了,您最好使用现有的解决方案。

其中一些最重要的是:

Doctrine

Propel

我曾经亲自使用过:

Idiorm

如果我没弄错的话,这三个都是建立在PDO上的,并使用预备语句。

如果您想为此制定自己的解决方案,PDO和准备好的陈述是一个非常好的主意,如果不是必须的话。