Dynamic PHP PDO insert method
You are using the prepared statement with placeholders properly, so regarding security, I would only advise you to not display the actual error details to the end user -- you don't want naughty people getting any funny ideas.

As for readability, I try not to declare single-use variables, though it can be good to declare a single-use variable to clarify the data being processed.

I don't prefer the over-delimit, then rtrim() technique.  Building a temporary array of ? then imploding it with commas seems cleaner to me.

$columns = implode(',', array_keys($data));

$placeholders = implode(',', array_fill(0, count($data), '?'));

$values = array_values($data);