A hacky way to emulate bind parameters into SQL query

@param $query
@param $bindings

@return mixed
970666
private function bind_params( $query, $bindings, $update = false )
	{

		$query    = str_replace( '"', '`', $query );
		$bindings = $this->prepareBindings( $bindings );

		if ( ! $bindings ) {
			return $query;
		}

		$bindings = array_map( function ( $replace )
		{
			if ( is_string( $replace ) ) {
				$replace = "'" . esc_sql( $replace ) . "'";
			} elseif ( $replace === null ) {
				$replace = "null";
			}

			return $replace;
		}, $bindings );

		$query = str_replace( [ '%', '?' ], [ '%%', '%s' ], $query );
		$query = vsprintf( $query, $bindings );

		return $query;
	}
365236
public function bindValues($query) {
        if (!empty($this->bind_values) && !empty($this->bind_keys)) {
            if (!$query instanceof \PDOStatement) {
                $this->setError('q', 'No valid PDO Statement provided');
            }

            for ($ii = 0; $ii < count($this->bind_values); $ii++) {
                $param = $this->get_PDO_param($this->bind_values[$ii]);
                $value = $this->bind_values[$ii];
                $key = $this->bind_keys[$ii];

                $query->bindValue($key, $value, $param);
            }
        }
    }
667195
public function positionalStatement(string $query, array $bindings = [])
    {
        return $this->run($query, $bindings, function ($query, $bindings) {
            if ($this->pretending()) {
                return 0;
            }
            $query = N1qlQuery::fromString($query);
            $query->consistency($this->consistency);
            $query->crossBucket($this->crossBucket);
            $query->positionalParams($bindings);
            $result = $this->executeQuery($query);
            $this->metrics = $result->metrics ?? [];
            if (!count($result->rows)) {
                return false;
            }

            return $result->rows[0]->{$this->bucket} ?? $result->rows[0];
        });
    }
97065
public function statement( $query, $bindings = [] )
	{
		$new_query = $this->bind_params( $query, $bindings, true );

		return $this->unprepared( $new_query );
	}
1189720
public function query($query=null, $params = [])
    {
        $result = false;
        $result_key = [];
        
        if ($query && static::isSql($query)) {
            $sql = $query;
        } else {
            $result_key = $this->getQuery()->set($query)->get('result_key');
            
            $queryType = $this->getQuery()->type();
            
            // limit select count
            if ((!$queryType || $queryType === 'select') 
                && !isset($this->getQuery()['count']) 
                && !isset($this->getQuery()['limit'])
                && !isset($this->getQuery()['pagesize'])) 
            {
                $this->getQuery()->set('limit', 1000);
            }
            
            // update must set where
            if (($queryType === 'update' || $queryType === 'delete') && !$this->getQuery()->get('where')) {
                Ioc::logger('db')->error('query no set where: ' . json_encode($this->getQuery()->all()));
                return false;
            }
            
            $sql = $this->parse();
        }
        
        if ($params) {
            $this->bindParams($params);
        }
        
        $this->lastSql = $this->formatSql($sql);
        
        // sql log
        Ioc::logger('db')->debug($sql);
        
        try {
            $this->getAdapter()->prepare($sql);
            if (!empty($this->binds)) {
                $this->getAdapter()->bindParams($this->binds);
            }
            $bool = $this->getAdapter()->execute();
            
            if (!$bool) {
                throw new Exception($this->getAdapter()->getErrorMessage());
            }
        } catch (Exception $e) {
            
            $this->getAdapter()->rollback();
            throw new Exception('Excute sql error: ' . $e->getMessage() . ', sql:' . $sql);
        }
        
        $rawStatement = explode(" ", $sql);
        $statement = strtolower(trim($rawStatement[0]));
        
        if ($statement === 'show') {
            $result = $this->getAdapter()->fetchAll($fetchmode);
        } elseif ($statement === 'select') {
            $rkeys = $result_key ? StringHelper::toArray($result_key, ',\s') : null;
            
            while($rs = $this->getAdapter()->fetch()) {
                // 如果指定返回结果集的key，则按key重组数据
                if ($rkeys) {
                    if (count($rkeys) == 1) {
                        $rk1 = trim($rkeys[0]);
                        if (isset($rs[$rk1])) {
                            $result[$rs[$rk1]] = $rs;
                        } else {
                            $result[] = $rs;
                        }
                    } elseif (count($rkeys) == 2) {
                        $rk1 = trim($rkeys[0]);
                        $rk2 = trim($rkeys[1]);
                        if (!empty($rk2)) {
                            $result[$rs[$rk1]][$rs[$rk2]] = $rs;
                        } else {
                            $result[$rs[$rk1]][] = $rs;
                        }
                    }
                } else {
                    $result[] = $rs;
                }
            }
        } elseif ($statement === 'update' || $statement === 'delete') {
            $result = $this->getAdapter()->numberOfRows();
        } elseif ($statement === 'insert') {
            $result = $this->getAdapter()->lastId();
        } else {
            return null;
        }
        
        return $result;
    }
1130453
public function select($query, $bindings = array())
	{
		return $this->run($query, $bindings, function($me, $query, $bindings)
		{
			if ($me->pretending()) return array();

			// For select statements, we'll simply execute the query and return an array
			// of the database result set. Each element in the array will be a single
			// row from the database table, and will either be an array or objects.
			$statement = $me->getReadPdo()->prepare($query);

			$statement->execute($me->prepareBindings($bindings));

			return $statement->fetchAll($me->getFetchMode());
		});
	}
1153316
public function setBindings($bindings): Query
    {
	    if (is_array($bindings)) {
		    $this->bindings = new Bindings();
		    $this->bindings->setFromArray($bindings);

	    } else if ($bindings instanceof Bindings) {
		    $this->bindings = $bindings;

	    } else {
		    throw new \InvalidArgumentException('Invalid second argument provided, expected null, array or instance of Bindings');
	    }

        return $this;
    }
890343
public static function hydrateRaw( $query, $bindings = [], $connection = null )
	{
		$instance = ( new static )->setConnection( $connection );

		$items = $instance->getConnection()->select( $query, $bindings );

		return static::hydrate( $items, $connection );
	}
548897
public function prepare($query, array $bindings=[])
    {
        $statement = $this->statement($query);

        $this->callBeforeListeners('prepare',[$query, $bindings]);

        $prepared = (new PDOPrepared(
            $statement,
            $query,
            $this->getOption(self::RETURN_LAST_AFFECTED),
            $this->errorHandler
        ))->bind($bindings);

        $this->callAfterListeners('prepare',[$query, $bindings, $prepared]);

        return $prepared;

    }
542784
public function select( $query, $bindings = [ ], $useReadPdo = true, $resultClass = null )
	{
		$fetchCustomClass = ! is_null($resultClass) && class_exists($resultClass);

		return $this->run( $query, $bindings, function ( $query, $bindings ) use ( $useReadPdo, $fetchCustomClass, $resultClass ) {
			if( $this->pretending() )
			{
				return [];
			}

			// For select statements, we'll simply execute the query and return an array
			// of the database result set. Each element in the array will be a single
			// row from the database table, and will either be an array or objects.
			$statement = $this->prepared( $this->getPdoForSelect( $useReadPdo )->prepare( $query ), ! $fetchCustomClass );
			$this->bindValues( $statement, $this->prepareBindings( $bindings ) );
			$statement->execute();

			return $fetchCustomClass ? $statement->fetchAll(\PDO::FETCH_CLASS, $resultClass) : $statement->fetchAll();
		});
	}
114820
public function toSQL($parseBindings = true) {
        $sql = $this->sql;
        if ($parseBindings && !empty($this->bindings)) {
            $sql = $this->xpdo->parseBindings($sql, $this->bindings);
        }
        return $sql;
    }
1014270
public function statements($query, $statements)
    {
        try {
            $query = $this->conn->prepare($query);

            foreach ($statements as $key => $value) {
                $param = $statements[$key][0];
                $value = $statements[$key][1];
                $ifExists = (isset($statements[$key][2]));
                $dataType = $ifExists ? $statements[$key][2] : false;

                switch ($dataType) {
                    case 'bool':
                        $query->bindValue($param, $value, \PDO::PARAM_BOOL);
                        continue;
                    case 'null':
                        $query->bindValue($param, $value, \PDO::PARAM_NULL);
                        continue;
                    case 'int':
                        $query->bindValue($param, $value, \PDO::PARAM_INT);
                        continue;
                    case 'str':
                        $query->bindValue($param, $value, \PDO::PARAM_STR);
                        continue;
                }

                $query->bindValue($param, $value);
            }

            $query->execute();

            return $query;
        } catch (\PDOException $e) {
            $this->error = $e->getMessage();

            return null;
        }
    }
418332
public function cursor( $query, $bindings = [], $useReadPdo = true )
	{
		$statement = $this->run( $query, $bindings, function ( $me, $query, $bindings ) use ( $useReadPdo )
		{
			if ( $me->pretending() )
			{
				return [];
			}

			$statement = $this->getPdoForSelect( $useReadPdo )->prepare( $query );

			$fetchMode = $me->getFetchMode();
			$fetchArgument = $me->getFetchArgument();

			if ( $fetchMode === PDO::FETCH_CLASS && !isset( $fetchArgument ) )
			{
				$fetchArgument = 'StdClass';
			}

			if ( isset( $fetchArgument ) )
			{
				$statement->setFetchMode( $fetchMode, $fetchArgument, $me->getFetchConstructorArgument() );
			}
			else
			{
				$statement->setFetchMode( $fetchMode );
			}

			$statement->execute( $me->prepareBindings( $bindings ) );

			return $statement;
		} );

		while ( $record = $statement->fetch() )
		{
			yield $record;
		}
	}
889306
protected function compileJoinPart(Query $query, array &$bindings): string
    {
        $joinsSQL = [];

        foreach ($query->join as $join) {
            $joinsSQL[] = $this->compileOneJoin($join, $bindings);
        }

        return $this->implodeSQL($joinsSQL);
    }
1306073
public function select($query, $bindings = [], $useReadPdo = true)
    {
        $query .= ' ALLOW FILTERING';

        return $this->statement($query, $bindings);
    }
122979
public function setQuery(string $query, $bindings = null): Query
    {
        $this->query = $query;

	    if ($bindings === null) {
		    $this->bindings = new Bindings();

	    } else if (is_array($bindings)) {
		    $this->bindings = new Bindings();
		    $this->bindings->setFromArray($bindings);

	    } else if ($bindings instanceof Bindings) {
		    $this->bindings = $bindings;

	    } else {
		    throw new \InvalidArgumentException('Invalid second argument provided, expected null, array or instance of Bindings');
	    }

        return $this;
    }
919274
public function query($query, array $binds = array())
    {
        //Argument 1 must be a string or null
        Argument::i()->test(1, 'string', self::QUERY);
        
        $request = new \stdClass();
        
        $request->query = $query;
        $request->binds = $binds;
        
        //event trigger
        $this->trigger('sql-query-before', $request);
        
        $connection = $this->getConnection();
        $query      = (string) $request->query;
        $stmt       = $connection->prepare($query);
        
        //bind some more values
        foreach ($request->binds as $key => $value) {
            $stmt->bindValue($key, $value);
        }
        
        //PDO Execute
        if (!$stmt->execute()) {
            $error = $stmt->errorInfo();
            
            //unpack binds for the report
            foreach ($binds as $key => $value) {
                $query = str_replace($key, "'$value'", $query);
            }
            
            //throw Exception
            Exception::i()
                ->setMessage(Exception::QUERY_ERROR)
                ->addVariable($query)
                ->addVariable($error[2])
                ->trigger();
        }
        
        $results = $stmt->fetchAll(\PDO::FETCH_ASSOC);
        
        if($this->queryCache) {
            //log query
            $this->queries[] = array(
                'query'     => $query,
                'binds'     => $binds,
                'results'   => $results);
        }

        //clear binds
        $this->binds = array();
        
        //event trigger
        $this->trigger('sql-query-after', $query, $binds, $results);
        
        return $results;
    }