There are several areas for improvement.
There is a fair possibility for the SQL injection. You are adding variables (namely array keys) into SQL query absolutely untreated, which is a big red flag.
Although your intended usage scenario is safe, but you cannot foresee any possible use case. There was an infamous SQL injection in Drupal 7 that used a code almost identical to yours - an array key is put into the query untreated. As you can see, it led to a severe vulnerability. Therefore, your function ought to offer a 100% safe query execution, no matter how it's called.
However, the best solution you can get will question the function's existence itself. Because the best way to protect the field names is to whitelist them, but the best way to whitelist table fields is... to list them explicitly in the query. And if you list them in the query, there will be no need for such a function at all. It shouldn't be a problem, however, as you are going to list your field names right in the code this way or another. Given you can use positional placeholders, the code could be reasonably small:
DB::query('INSERT INTO posts (name, content) VALUES (?,?)', [
Whereas a function like
DB::insert() could be justified not as a free-to-use function, but as method belongs to an ORM, that operates a predefined set of object's properties only. In this case, when it's guaranteed that only predefined field names are allowed to the query, such a function could be used safely.
If you are 100% determined to use this function as is, at least make sure you are quoting and escaping field and table names properly.
The error reporting is completely flawed in this function. It tells everyone that you don't even consider your site to go live. Because present error reporting is only useful for the single-user dev mode, while it would be completely useless (and even harmful) on a live site. I've got a comprehensive guide on PHP error reporting, but in short, you must leave an error/exception alone and let it to bubble up to the site-wide handler, instead of catching it on the spot.
A generic query function.
From the code of your function it is evident that you don't have a generic query function (or you don't reuse its code which is equally bad). There should be a function that accepts a query and an array with parameters, and returns a statement:
public static function query($query, $data = )
$statement = static::$connection->prepare($query);
and then it could be used in your insert() method (as well as in many other methods):
$query = "INSERT INTO $table ($columnsString) VALUES ($valuesPlaceholder)";
(but again - remember that $table and values in $columnsString must be either quoted/escaped or - preferably - hardcoded in the class definition).
A proper Model
Your code hints that you are intending to follow the MVC pattern. However, the code in your controller is not reusable, it means that the pattern is broken. Imagine you are going to create a command-line utility to create posts. Or any other method like creating a post through e-mail. You will inevitably duplicate this insert call, which is against the very purpose of the MVC pattern.
So, to make it proper, you must create a Post Service with a create() method in it, whic would be called in your Controller. It will make your Controller thin, and the insert code reusable.