Compile Bindings
Take From CI 3 Database Query Builder, default string Binding use Question mark ( ? )

@param   string $sql   sql statement
@param   array  $binds array of bind data
@return  mixed
765065
public function compileBindsQuestionMark(string $sql, $binds = null)
    {
        if (empty($binds) || strpos($sql, '?') === false) {
            return $sql;
        } elseif (! is_array($binds)) {
            $binds = [$binds];
            $bind_count = 1;
        } else {
            // Make sure we're using numeric keys
            $binds = array_values($binds);
            $bind_count = count($binds);
        }
        // Make sure not to replace a chunk inside a string that happens to match the bind marker
        if ($countMatches = preg_match_all("/'[^']*'/i", $sql, $matches)) {
            $countMatches = preg_match_all(
                '/\?/i', # regex
                str_replace(
                    $matches[0],
                    str_replace('?', str_repeat(' ', 1), $matches[0]),
                    $sql,
                    $countMatches
                ),
                $matches, # matches
                PREG_OFFSET_CAPTURE
            );
            // Bind values' count must match the count of markers in the query
            if ($bind_count !== $countMatches) {
                return false;
            }
        } elseif (($countMatches = preg_match_all('/\?/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count) {
            return $sql;
        }

        do {
            $countMatches--;
            $escapedValue = is_int($binds[$countMatches])
                ? $binds[$countMatches]
                : $this->quote($binds[$countMatches]);
            if (is_array($escapedValue)) {
                $escapedValue = '('.implode(',', $escapedValue).')';
            }
            $sql = substr_replace($sql, $escapedValue, $matches[0][$countMatches][1], 1);
        } while ($countMatches !== 0);

        return $sql;
    }
365925
public function prepare($sql)
    {
        $this->_connect();
        $stmtClass = $this->_defaultStmtClass;
        $stmt = new $stmtClass($this, $sql);
        $stmt->setFetchMode($this->_fetchMode);
        return $stmt;
    }
708052
public function build ($sql, $bind = array())
    {
        // stdclassの場合はarrayにキャスト
        if ($bind instanceof \stdClass) {
            $bind = (array) $bind;
        }

        // 配列でない場合は配列化
        if (! is_array($bind)) {
            $bind = array($bind);
        }

        // mysql strict mode 対策　STRICT_TRANS_TABLES、STRICT_ALL_TABLES
        // http://dev.mysql.com/doc/refman/5.1/ja/server-sql-mode.html
        // booleanをintに変更
        foreach($bind as $key => $val) {
            if (is_bool($val) === true) {
                $bind[$key] = (int) $val;
            }
        }

        $stmt = $this->prepare($sql);
        $stmt->execute($bind);

        return $stmt;
    }
854553
public function query($sql, $bind = array())
    {
        $this->prepare($sql, $bind);

        return $this->db->query($sql, $bind);
    }
842257
public function havingRaw(string $sql, array $bindings = []): BaseQueryRelateContract
    {
        $this->query->havingRaw($sql, $bindings, 'and');

        return $this;
    }
154619
protected function compileOneJoin(Join $join, array &$bindings): string
    {
        $sql = $join->type.' JOIN '.$this->compileIdentifierWithAlias($join->table, $join->tableAlias, $bindings);

        if ($join->criteria) {
            $sql .= ' ON '.$this->compileCriteria($join->criteria, $bindings);
        }

        return $sql;
    }
247570
protected function bindValues(/*# string */ $sql, array $settings)/*# : string */
    {
        // init bindings
        $this->bindings = [];

        // bind values
        return $this->getBuilder()->getParameter()
            ->bindValues($sql, $this->bindings, $settings);
    }
540734
public function query($sql, $bind = [], $master = false, $class = false)
    {
        return $this->connection->query($sql, $bind, $master, $class);
    }
625720
public function prepareBindingsForUpdate(array $bindings, array $values)
    {
        $values = collect($values)->map(function ($value, $column) {
            return $this->isJsonSelector($column) && ! $this->isExpression($value)
                ? json_encode($value)
                : $value;
        })->all();

        // Update statements with "joins" in Postgres use an interesting syntax. We need to
        // take all of the bindings and put them on the end of this array since they are
        // added to the end of the "where" clause statements as typical where clauses.
        $bindingsWithoutJoin = Arr::except($bindings, 'join');

        return array_values(
            array_merge($values, $bindings['join'], Arr::flatten($bindingsWithoutJoin))
        );
    }
394322
public function query($sql, $bindings = array())
    {
        list($this->pdoStatement) = $this->statement($sql, $bindings);

        return $this;
    }
563387
public function statement($query, $bindings = [])
    {
        $new_query = $this->bindParams($query, $bindings, true);

        return $this->unprepared($new_query);
    }
1150230
public function fetchPairs($sql, $bind = array())
    {
        $stmt = $this->query($sql, $bind);
        $data = array();
        while ($row = $stmt->fetch(Zend_Db::FETCH_NUM)) {
            $data[$row[0]] = $row[1];
        }
        return $data;
    }
114820
public function toSQL($parseBindings = true) {
        $sql = $this->sql;
        if ($parseBindings && !empty($this->bindings)) {
            $sql = $this->xpdo->parseBindings($sql, $this->bindings);
        }
        return $sql;
    }
647737
public function orHavingRaw(string $sql, array $bindings = []): BaseQueryRelateContract
    {
        $this->query->orHavingRaw($sql, $bindings);

        return $this;
    }
4830
public function prepareSQL($sql, $binds = [])
    {
        $prepare = $this->getConnection()->prepare($sql);

        if (!$prepare) {
            throw new Exception('Cannot prepare statement');
        }

        $this->bindBinds($prepare, $binds);

        $prepare->setFetchMode(\PDO::FETCH_OBJ);

        return $prepare;
    }
1080330
public function queryCache($sql, $bind = []) {
        $redis = Cache::redis();
        if (!$redis) {
            //没有使用 redis 不支持二级缓存
            return null;
        }
        $key = $this->cacheKey($sql, $bind);
        $cache_name = $this->cacheName($sql);
        $result = Cache::hashGet($cache_name, $key);
        if ($result) {
            Log::debug("命中缓存" . $sql . json_encode($bind), 'cache');
        }
        return $result;
    }
97065
public function statement( $query, $bindings = [] )
	{
		$new_query = $this->bind_params( $query, $bindings, true );

		return $this->unprepared( $new_query );
	}