I am currently working on a ton of Web Services related things for the Zend Framework, one of my favorite, is the almost complete, Zend_Rest_Client. This is a replacement for Zend_Rest (as we're adding a server also).
Whilst it is almost impossible to emulate the PHP 5 SOAP extension, it is still possible to get a nice interface.
I could have made it so that if you call a method, other than the get/post/put/delete methods it would query a Zend REST server correctly, however I wanted to do something nice that was applicable to all REST web services. So I have come up with a client that allows the following three calls:
<?php
$client = new Zend_Rest_Client('http://.../service.php');
echo $client->sayHello('Davey', 'Day')->get();
?>
This first one connects to a Zend_Rest_Server, and it therefore knows the format of the response and returns a string (in this case, it can also return arrays) directly from the get() call. The entire function will send the request:
http://..../service.php?method=sayHello&arg1=Davey&arg2=Day which the Zend_Rest_Server will translate to the TestClass::sayHello($who, $when); call (though it's not a static call). TestClass is the class registered with the server - just like ext/soap.
Furthermore, there is a "fluent" API, for regular REST services:
<?php
$client = new Zend_Rest_Client('http://api.flickr.com/services/rest/');
echo $client->method('flickr.test.echo')->name('Davey Shafik')->api_key($flickr_key)->get()->name;
?>
This time, we need to access the name property on the return value for get(), this is because we don't know the format of the response (it's a call to the Flickr REST service), but you do. If there is only one node called name in the XML, we return it as a string (it's overloaded), otherwise, you will get a SimpleXMLElement array (more on this after the next example); or null for nothing found.
This time, it calls http://api.flickr.com/services/rest/?method=flickr.test.echo&name=Davey%20Shafik&api_key={api key}.
The final look for a call, is just calling things normally, no fluentness:
<?php
$technorati = new Zend_Rest_Client('http://api.technorati.com/bloginfo');
$technorati->key($key);
$technorati->url('http://pixelated-dreams.com');
$result = $technorati->get();
echo $result->firstname .' '. $result->lastname;
?>
Here it calls http://api.technorati.com/bloginfo?key={key}&url=http%3A%2F%2Fpixelated-dreams.com.
In this example, we call directly on $result->firstname and $result->lastname - these don't exist in the root node of the XML returned, but to make things easier, if it is not found, an XPath for (in these cases) firstname and lastname is called respectively. Again a string (shown here) or a SimpleXMLElement array is returned for multiple elements. These calls actually get the
document->result->weblog->author->firstname and document->result->weblog->author->lastname elements.
Whilst this could cause some problems (where same-named nodes are in different portions of the resulting XML and you want a specific one), you can still always access the elements as if the result was a SimpleXMLElement root node directly - this is simply a convenience that obviously pays off in this example.
The only outstanding item I have left is to recursively turn Zend_Rest_Server array responses into real arrays, this will stop you needed to (string) the nodes to use them. I think I will accomplish this using a wrapper object that implements ArrayAccess - this ensures the same result API those services that do use Zend_Rest_Server and those that don't, whilst allowing OO access to the resulting values.
- Davey
P.S.
Eat My Shorts RoR 