Replacing $ in the MongoDB PHP Driver

I’ve just added a feature to the Mongo PHP driver (and I plan to add it to the Perl driver soon) to use a character other than $ for special ops.

In Mongo, there are tons of interesting things you can do by using $-prefixed strings:

// run a server-side function as part of a query
db.collection.find({$where : function() { ... });
// increment a field in an update
db.collection.update({_id : id}, {$inc : {counter : 1}});
// add more cowbell to an array
db.collection.update({_id : id}, {$push : {life : "cowbell"}});

There are a gazillion more, and we keep adding them. Anyway, it’s a bit of a pain in PHP (and Perl) because “$var” means “replace $var with the variable $var and convert it to a string.” As there is probably no $var variable, it’s null, and null converted to a string is “”. So, instead of the string “$var”, you get “”. Of course, you can prevent this by saying “\$var” or ‘$var’ (single quotes), but people have requested being able to use a different character, instead of $.

I considered choosing one for people, but then I decided it was better to let people choose their own. So, if you want to use the character with the ASCII value of 0, go nuts (anyone who maintains your code certainly will).

To choose an alternative, add a line to your php.ini file:

mongo.cmd = "+"

…replacing “+” with whatever symbol you’d like to use. If you do not have access to your php.ini file or you feel like being a jerk (I think doing this makes your code pretty impenetrable), you can change it anywhere in your code with ini_set:

// use : for an update (instead of $inc)
ini_set("mongo.cmd", ":");
$collection->update(array("_id" => $id), array(":inc" => array("counter" => 1)));
// use > (instead of the $cmd collection)
ini_set("mongo.cmd", ">");
$cmdCollection = $db->selectCollection(">cmd");
$cmdCollection->findOne(array("getlasterror" => 1));
// use x for db refs (this is a particularly bad idea, use a character that 
// won't occur as the first character of a key name)
ini_set("mongo.cmd", "x");
$collection->insert(array("ref" => array("xref" => $ns, "xid" => $id)));

My recommendation is to decide on an alternative character and stick with it.

Some technical details:

  • $ will still work. Even if you choose another character, you can still use $s, too.
  • Only the first character will be replaced by $. So, if you chose “~” as your substitute character, “~~~” would be sent to the database as “$~~”.
  • I made this work in all of the places I could think of where you’d need a $ (key names, database references, and collection names). If you think of any others, please let me know so I can add them
  • Thank you for doing this, I agree that only jerks use ini_set.

kristina chodorow's blog