Using Magic Methods to Call Remote Functions
Have you ever wanted to directly call a function or method that is in a script on another server? I know it sounds crazy, but stay with me here. Initially, my answer to this solution was to write an XML interface, which seemed entirely logical especially since both sides of the equation weren’t necessarily running in PHP.
So to execute a service on another machine, the front-end server would have an object definition, which would both provide a defined structure for the object (such as a payment), as well as offering some common methods to perform a remote request to the backend server to actually do some work. When the object was ready to do something, it would call its own request method, passing in a URL to an interface page, and the request method would handle building an XML request based on the properties of the object, posting the XML to the page that was passed in, and then returning the XML response when all was done. On the other side of the picture, the page that is handling the request would in turn initialize a similarly structured object, which was defined with the necessary methods to perform the work requested (such as processing a payment). For example, in order to call the MakePayment method on the payment object, the frontend would need a MakePayment method, which sets up the payment details and initiates the XML request, and then the XML interface would need a handler created to set up the payment and handle calling the MakePayment method on the actual object on the backend server.
Definitely not the most elegant solution, but it made the most sense when we originally encountered the need to pass requests between servers, particularly due to the language differences I mentioned earlier.
Some of the best and craziest ideas happen by chance, and that’s exactly how I stumbled upon this idea. A coworker was having some difficulty with one of the services, and was slightly confused by which code was causing the problem, as there were effectively four components in the mix — the display page on the frontend, the service’s object definition, the XML interface on the backend server, and the “real” object definition there. After seeing the error he was getting and having a look at the code, I determined the problem was that he was just missing a method definition on the frontend, and would need to create one. When I explained this, however, he responded with a simple question: "Why can’t I just call this method directly?" My initial response, of course, was to say "because it’s on another server" and that you can’t simply make calls across systems like that, but then I started wondering exactly the same thing — why not?
I knew that you could transfer information across systems easily by storing session data in a shared database, and I started to wonder why a similar principle wouldn’t work for directly calling methods. So the solution I came up with is actually relatively simple: serialize the request object and send the entire object over the POST to the other server. The handler on that server just needs to unserialize it there, and call the requested method, and then serialize and return the response. I further simplified this by defining a
__call “magic method” on the template object that automatically facilitates the request, allowing you to call any method that is defined on the backend server’s object in the code on the frontend without having to define the methods on both servers.
There are, of course, some gotchas to watch out for (some objects can’t be easily serialized, such as
SimpleXMLElement), but for the most part this works pretty well and requires very little code to function on the frontend server.