Thank you for the great question.
As a matter of fact, you could use both methods at once.
Most people do confuse the idea of a prepared statement in general with [very limited] implementation offered by major DBMS. While the latter can be questioned, the former is indeed the only way.
Take a look at the example. Let's run your query using safeMysql:
$sql = "UPDATE SET column1 = ?i, column2 = ?s WHERE column3 = ?s AND column4 = ?s";
$db->query($sql, $string, $blob, $int, $double);
It performs the very string formatting like your code does, but does it internally. Why? Because it doesn't matter how it's implemented internally (by means of native prepared statement or manual formatting), but it is essential to use a prepared statement to assembly your query either way.
There are some essential points about prepared statements, overlooked by most people:
it makes formatting being always complete (Although in your example you're doing the right thing and make complete formatting, it is still very easy to slip into incomplete one, like this:
$colname = "`$colname`";
your formatting being always the right one. it won't let you do something like
$colname = "`" .mysql_real_escape_string($colname) ."`";
which would be useless and lead you to injection
it will make formatting obligatory. With assembling a query your current way it is very easy to overlook a variable or two.
- it will do proper formatting as close to the query execution as possible. That's the point of great importance, as
- it will not spoil your source variable (what if query failed and you want to echo it back?)
- it won't let you to move formatting code somewhere away from the query, which may lead to fatal consequences.
- after all, it will make your code dramatically shorter, without all that boring manual formatting!
That's the real benefits of a prepared statements, which guarantee the safety and thus made them so overly popular. While that thing with server-side preparation, although being quite smart, is just a particular implementation.
Also, taking the idea of a prepared statement as a guide, one can create a placeholder for the everything that may be added into query (an identifier or an array for example), making it real safe and convenient to use.
Keeping all the things in mind one have to implement the very idea of a prepared statement in their DB access library, to make the code safe and short.
Just a couple of examples from safeMysql:
$name = $db->getOne('SELECT name FROM table WHERE id = ?i',$_GET['id']);
$data = $db->getInd('id','SELECT * FROM ?n WHERE id IN ?a','table', array(1,2));
$data = $db->getAll("SELECT * FROM ?n WHERE mod=?s LIMIT ?i",$table,$mod,$limit);
$ids = $db->getCol("SELECT id FROM tags WHERE tagname = ?s",$tag);
$data = $db->getAll("SELECT * FROM table WHERE category IN (?a)",$ids);
$data = array('offers_in' => $in, 'offers_out' => $out);
$sql = "INSERT INTO stats SET pid=?i,dt=CURDATE(),?u ON DUPLICATE KEY UPDATE ?u";
$db->query($sql,$pid,$data,$data);
Just try the same with conventional mysql(i) and see the amount of code it takes you.
You may note that with usable prepared statements you have to mark them with type, because there are more types than just simple string, and it's the only reliable way to tell a driver how to format your variable.