Sunday 20 October 2013

Reading more

Well, I did some more reading on error handling in javascript this morning, and I didn't find anything to dissuade me from using exceptions. Here's a presentation on slideshare from the author of "Professional Javascript for Web Developers":

I'm not quite sure about the window.onerror thing, as it only seems to 'catch' error events rather than exceptions. I'm not 100% convinced that catching and logging js errors is going to be that useful either, especially when using a third party library that may be causing the errors.

And here's another resource that agrees with my way of thinking: Eloquent Javascript | Chapter 5: Error Handling. (Though I disagree with the use of Exceptions in their final example, which seems more like a hack than a proper use of Exceptions).

I also found that you can implement getter and setter methods that are called automatically when a property is accessed, see: MDN: Using <propertiesObject> argument with Object.create. Just to include the relevant part here:

// Example where we create an object with a couple of sample properties.
// (Note that the second parameter maps keys to *property descriptors*.)
o = Object.create(Object.prototype, {
  // foo is a regular "value property"
  foo: { writable:true, configurable:true, value: "hello" },
  // bar is a getter-and-setter (accessor) property
  bar: {
    configurable: false,
    get: function() { return 10 },
    set: function(value) { console.log("Setting `o.bar` to", value) }
}});
o.bar //10
o.bar=20 //Setting `o.bar` to 20
o.bar //10

I was reading some more of the Sitepoint 'PHP Master' book, and got the section about using a database. Their examples (nearly) all use prepared statements, which I was under the impression was only recommended if you need to execute the same statement more than once, but with different (or the same) values. Looking up the section about prepared statements for mysqli in the PHP Manual seems to confirm my view.

However, the sitepoint book uses PDO rather than mysqli. I wondered how you would execute a query in PDO without using a prepared statement, but still making sure that string values were escaped. It turns out that you can use PDO::quote, however the PHP Manual states (emphasis mine):

If you are using this function to build SQL statements, you are strongly recommended to use PDO::prepare() to prepare SQL statements with bound parameters instead of using PDO::quote() to interpolate user input into an SQL statement. Prepared statements with bound parameters are not only more portable, more convenient, immune to SQL injection, but are often much faster to execute than interpolated queries, as both the server and client side can cache a compiled form of the query.

As far as I am aware, the server only caches the statement for that session. How many times do I run the same query more than once with some of the parameters changed? On most front facing pages on my websites the answer would be none. On the backend pages, it is much more likely.

I think the answer is going to have to be to run some tests. Something like a select and insert query, each run once, 5 times, 10 times, 100 times, and a thousand times. And each with mysqli, PDO with prepared statements, and PDO with PDO::quote. However, I am pretty sure I remember seeing a test done a few ago and mysqli without prepared statements was quite a lot faster than PDO with prepared statements for anything other than a large number of repeated queries. We shall see.

Well, after church and lunch, before getting started on my testing, I read this: Are PDO prepared statements sufficient to prevent SQL injection? and it has saved from needing to do any testing. Basically, that answer says that PDO does not use true prepared statements by default. It just calls mysql_escape_string on the parameters.

I would be very surprised if PDO was faster than mysqli, but it is good to know that it doesn't make two round trips to the db for just a standard query. It seems like a sensible solution would be calling $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); for stuff where you do need the same query run multiple times, so you get real prepared statements. And then leaving it at the default setting for the majority of situations where you just running each query once.

No comments: