If you’ve followed Tim O’Reilly‘s theme for the last few years, the Internet Operating System, then maybe you are also wondering what sort of steps will be needed to really make such things possible. Back in October 2003 he listed a few “basic” features revolving around the idea that all applications should be network aware. It was thinking with these things in mind that I came up with what seemed to be a simple idea, what if you could expose an entire programming language (more or less) as a web service? Let me scale that back a bit, what if you could expose all of the functions for a programming language as a web service? Would doing so even be possible without a lot of hand holding in the code? So just to see where that might go I wanted to try it out.
I’m doing most of my work lately in PHP so I picked that as my target. Right off the back PHP saved me a lot headache by making use of get_defined_functions() to get a list of PHP’s functions (along with any user defined functions). There are plenty of XML-RPC PHP libraries out there, for this project I went with Simon Willison‘s nicely done XML-RPC library for PHP. I did have to make one small change, I removed the method signature enforcement from the IXR_IntrospectionServer class because I had no way of determining what the correct signature should be for each function without writing customer code for each function, which I didn’t want to do. It’s a fairly small change, you can grab my modified version if you want to try this at home. The PHP over XML-RPC server simply goes through all of the PHP functions and adds callbacks for each one. All of the internal PHP functions are under php.*
and user defined functions are under php_user.*
. Take a quick look at it, it gets the job done in about 30 lines of code.
So what can you do with such a beast? An over simplification is that you can now access all of the internal PHP functions. A more correct analysis would be you can access all of the PHP functions, but some of them aren’t very useful over XML-RPC, like database functions. Other functions work but have reduced functionality, like preg_match which can optionally populate an array with matches from the given regular expression. That doesn’t work in our case because we can only return one value. Getting the return value works fine, but to make the match array work would require code to deal with exactly that function, which something I was trying to avoid. Here is a client example that does work as expected, calling PHP’s strlen:
## ## PHP over XML-RPC client ## require('./IXR_Library.inc.php'); $client = new IXR_Client('http://localhost/php-rpc/server.php'); if(!$client->query('php.strlen', 'teststring')) { print("Error: (" . $client->getErrorCode() . ") " . $client->getErrorMessage()); exit(); } print("PHP over XML-RPC: php.strlen('teststring'): "); print($client->getResponse());
The big downside for something like this is speed, using XML-RPC adds considerable overhead. In my simple benchmarks for strlen('teststring')
, natively it takes about 0.0000730 seconds, using PHP over XML-RPC it takes about 0.1438220 seconds. I’m sure that this could be made to vary by either using different XML-RPC libraries or moving to something completely different like SOAP. I doubt that either of those options would increase the speed much. The speed hit is simply too much to take, but this was all just an experiment anyway.
It might be interesting to see what it would take to create structures that would support database operations. This would increase the complexity of the server but would add some useful possibilities. If you didn’t like the Java approach to your database you could use PHP’s database functions over XML-RPC. The speed hit would still be the killer hold up making this realistic though.