This is one of those “I need to make a note of this in case I’m second-guessing myself in the future about why I made a certain technical decision” posts.
The issue at hand is how to best deal with error conditions inside a class that is being exposed via Zend_Soap_Server. Ideally, in the case of, say, an invalid parameter, you want the client to receive a SOAP Fault document containing an error code and message.
As it stands, Zend_Soap_Server will catch most errors that occur in the class whose method is being run and convert them into SOAP Fault documents that are sent to the client. The best way I’ve found of raising application errors is by using trigger_error( ’Error Message’, E_USER_ERROR )
. The only downside of this approach is that there doesn’t seem to be a way of passing in an error code, just a message, which is probably because of this code in Zend_Soap_Server.php:
// Set Zend_Soap_Server error handler
$displayErrorsOriginalState = ini_get(’display_errors');
ini_set('display_errors', false);
set_error_handler(array($this,'handlePhpErrors'), E_USER_ERROR);
and this...
public function handlePhpErrors($errno, $errstr, $errfile = null,
$errline = null, array $errcontext = null)
{
throw $this->fault($errstr, "Receiver");
}
Although this is slightly annoying, it does mean that the class being exposed can raise errors without needing to know that it is being exposed via SOAP.
If you want to raise an error and include an error code, thrown a SoapFault() exception.
Here’s the test code that I used to play around with the various options:
set_include_path( PATH_TO_ZEND_LIBRARY . get_include_path());
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();
if ( isset( $_GET['wsdl']))
{
$auto = new Zend_Soap_AutoDiscover();
$auto->setClass('Foo');
$auto->handle();
}
else if ( isset($_GET['ping']))
{
$client = new Zend_Soap_Client('http://localhost/zstest.php?wsdl');
try
{
echo $client->ping('Hello World!'), '<br />';
}
catch ( Exception $e )
{
echo 'Exception caught: ', $e->faultcode , ' - ',
$e->faultstring, '<br />';
}
echo htmlentities( $client->getLastResponse());
}
else
{
$server = new Zend_Soap_Server( 'http://localhost/zstest.php?wsdl' );
$server->setClass( 'Foo' );
$server->handle();
}
class Foo
{
/**
* @param string $testData
* @return string
*/
public function ping( $testData )
{
// throw new SoapFault( '1', 'Die' ); /* Error code and message passed
back in SOAP Fault document. */
// die( 'Die' ); /* SOAP Fault document is NOT returned by server. */
// trigger_error('Die', E_USER_ERROR); /* Best compromise. */
return $testData;
}
}
Please feel free to leave a comment if you have any thoughts on this issue.