summaryrefslogtreecommitdiff
path: root/php/src
diff options
context:
space:
mode:
Diffstat (limited to 'php/src')
-rw-r--r--php/src/IcePHP/Endpoint.cpp36
-rw-r--r--php/src/IcePHP/Init.cpp18
-rw-r--r--php/src/IcePHP/Operation.cpp156
-rw-r--r--php/src/IcePHP/Proxy.cpp80
-rw-r--r--php/src/IcePHP/Types.cpp470
-rw-r--r--php/src/IcePHP/Types.h74
-rw-r--r--php/src/IcePHP/Util.cpp375
-rw-r--r--php/src/IcePHP/Util.h22
8 files changed, 1054 insertions, 177 deletions
diff --git a/php/src/IcePHP/Endpoint.cpp b/php/src/IcePHP/Endpoint.cpp
index 85449b00ec6..a0f3829c010 100644
--- a/php/src/IcePHP/Endpoint.cpp
+++ b/php/src/IcePHP/Endpoint.cpp
@@ -286,6 +286,10 @@ IcePHP::endpointInit(TSRMLS_D)
ce.create_object = handleEndpointInfoAlloc;
endpointInfoClassEntry = zend_register_internal_class(&ce TSRMLS_CC);
memcpy(&_endpointInfoHandlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ zend_declare_property_null(endpointInfoClassEntry, STRCAST("protocol"), sizeof("protocol") - 1,
+ ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_null(endpointInfoClassEntry, STRCAST("encoding"), sizeof("encoding") - 1,
+ ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_long(endpointInfoClassEntry, STRCAST("timeout"), sizeof("timeout") - 1, 0,
ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_bool(endpointInfoClassEntry, STRCAST("compress"), sizeof("compress") - 1, 0,
@@ -327,14 +331,6 @@ IcePHP::endpointInit(TSRMLS_D)
#endif
ce.create_object = handleEndpointInfoAlloc;
udpEndpointInfoClassEntry = zend_register_internal_class_ex(&ce, ipEndpointInfoClassEntry, NULL TSRMLS_CC);
- zend_declare_property_long(udpEndpointInfoClassEntry, STRCAST("protocolMajor"), sizeof("protocolMajor") - 1, 0,
- ZEND_ACC_PUBLIC TSRMLS_CC);
- zend_declare_property_long(udpEndpointInfoClassEntry, STRCAST("protocolMinor"), sizeof("protocolMinor") - 1, 0,
- ZEND_ACC_PUBLIC TSRMLS_CC);
- zend_declare_property_long(udpEndpointInfoClassEntry, STRCAST("encodingMajor"), sizeof("encodingMajor") - 1, 0,
- ZEND_ACC_PUBLIC TSRMLS_CC);
- zend_declare_property_long(udpEndpointInfoClassEntry, STRCAST("encodingMinor"), sizeof("encodingMinor") - 1, 0,
- ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_string(udpEndpointInfoClassEntry, STRCAST("mcastInterface"), sizeof("mcastInterface") - 1,
STRCAST(""), ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_long(udpEndpointInfoClassEntry, STRCAST("mcastTtl"), sizeof("mcastTtl") - 1, 0,
@@ -350,6 +346,8 @@ IcePHP::endpointInit(TSRMLS_D)
#endif
ce.create_object = handleEndpointInfoAlloc;
opaqueEndpointInfoClassEntry = zend_register_internal_class_ex(&ce, endpointInfoClassEntry, NULL TSRMLS_CC);
+ zend_declare_property_null(opaqueEndpointInfoClassEntry, STRCAST("rawEncoding"), sizeof("rawEncoding") - 1,
+ ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_null(opaqueEndpointInfoClassEntry, STRCAST("rawBytes"), sizeof("rawBytes") - 1,
ZEND_ACC_PUBLIC TSRMLS_CC);
@@ -410,10 +408,6 @@ IcePHP::createEndpointInfo(zval* zv, const Ice::EndpointInfoPtr& p TSRMLS_DC)
Ice::UDPEndpointInfoPtr info = Ice::UDPEndpointInfoPtr::dynamicCast(p);
if((status = object_init_ex(zv, udpEndpointInfoClassEntry)) == SUCCESS)
{
- add_property_long(zv, STRCAST("protocolMajor"), static_cast<long>(info->protocolMajor));
- add_property_long(zv, STRCAST("protocolMinor"), static_cast<long>(info->protocolMinor));
- add_property_long(zv, STRCAST("encodingMajor"), static_cast<long>(info->encodingMajor));
- add_property_long(zv, STRCAST("encodingMinor"), static_cast<long>(info->encodingMinor));
add_property_string(zv, STRCAST("mcastInterface"), const_cast<char*>(info->mcastInterface.c_str()), 1);
add_property_long(zv, STRCAST("mcastTtl"), static_cast<long>(info->mcastTtl));
}
@@ -423,6 +417,12 @@ IcePHP::createEndpointInfo(zval* zv, const Ice::EndpointInfoPtr& p TSRMLS_DC)
Ice::OpaqueEndpointInfoPtr info = Ice::OpaqueEndpointInfoPtr::dynamicCast(p);
if((status = object_init_ex(zv, opaqueEndpointInfoClassEntry)) == SUCCESS)
{
+ zval* rawEncoding;
+ MAKE_STD_ZVAL(rawEncoding);
+ createEncodingVersion(rawEncoding, info->rawEncoding TSRMLS_CC);
+ add_property_zval(zv, STRCAST("rawEncoding"), rawEncoding);
+ zval_ptr_dtor(&rawEncoding); // add_property_zval increased the refcount of rawEncoding
+
zval* rawBytes;
MAKE_STD_ZVAL(rawBytes);
array_init(rawBytes);
@@ -456,6 +456,18 @@ IcePHP::createEndpointInfo(zval* zv, const Ice::EndpointInfoPtr& p TSRMLS_DC)
add_property_long(zv, STRCAST("port"), static_cast<long>(info->port));
}
+ zval* protocol;
+ MAKE_STD_ZVAL(protocol);
+ createProtocolVersion(protocol, p->protocol TSRMLS_CC);
+ add_property_zval(zv, STRCAST("protocol"), protocol);
+ zval_ptr_dtor(&protocol); // add_property_zval increased the refcount of protocol
+
+ zval* encoding;
+ MAKE_STD_ZVAL(encoding);
+ createEncodingVersion(encoding, p->encoding TSRMLS_CC);
+ add_property_zval(zv, STRCAST("encoding"), encoding);
+ zval_ptr_dtor(&encoding); // add_property_zval increased the refcount of encoding
+
add_property_long(zv, STRCAST("timeout"), static_cast<long>(p->timeout));
add_property_bool(zv, STRCAST("compress"), static_cast<long>(p->compress));
diff --git a/php/src/IcePHP/Init.cpp b/php/src/IcePHP/Init.cpp
index 9da2f13db9a..5f2f3f7d3a0 100644
--- a/php/src/IcePHP/Init.cpp
+++ b/php/src/IcePHP/Init.cpp
@@ -74,13 +74,27 @@ ZEND_END_ARG_INFO()
#define ICEPHP_UTIL_FUNCTIONS \
ZEND_FE(Ice_stringVersion, NULL) \
ZEND_FE(Ice_intVersion, NULL) \
- ZEND_FE(Ice_generateUUID, NULL)
+ ZEND_FE(Ice_generateUUID, NULL) \
+ ZEND_FE(Ice_currentProtocol, NULL) \
+ ZEND_FE(Ice_currentProtocolEncoding, NULL) \
+ ZEND_FE(Ice_currentEncoding, NULL) \
+ ZEND_FE(Ice_protocolVersionToString, NULL) \
+ ZEND_FE(Ice_stringToProtocolVersion, NULL) \
+ ZEND_FE(Ice_encodingVersionToString, NULL) \
+ ZEND_FE(Ice_stringToEncodingVersion, NULL)
#ifdef ICEPHP_USE_NAMESPACES
# define ICEPHP_UTIL_NS_FUNCTIONS \
ZEND_NS_FALIAS("Ice", stringVersion, Ice_stringVersion, NULL) \
ZEND_NS_FALIAS("Ice", intVersion, Ice_intVersion, NULL) \
- ZEND_NS_FALIAS("Ice", generateUUID, Ice_generateUUID, NULL)
+ ZEND_NS_FALIAS("Ice", generateUUID, Ice_generateUUID, NULL) \
+ ZEND_NS_FALIAS("Ice", currentProtocol, Ice_currentProtocol, NULL) \
+ ZEND_NS_FALIAS("Ice", currentProtocolEncoding, Ice_currentProtocolEncoding, NULL) \
+ ZEND_NS_FALIAS("Ice", currentEncoding, Ice_currentEncoding, NULL) \
+ ZEND_NS_FALIAS("Ice", protocolVersionToString, Ice_protocolVersionToString, NULL) \
+ ZEND_NS_FALIAS("Ice", stringToProtocolVersion, Ice_stringToProtocolVersion, NULL) \
+ ZEND_NS_FALIAS("Ice", encodingVersionToString, Ice_encodingVersionToString, NULL) \
+ ZEND_NS_FALIAS("Ice", stringToEncodingVersion, Ice_stringToEncodingVersion, NULL)
#else
# define ICEPHP_UTIL_NS_FUNCTIONS
#endif
diff --git a/php/src/IcePHP/Operation.cpp b/php/src/IcePHP/Operation.cpp
index 5bdf6ddc20b..ff1ad8b7805 100644
--- a/php/src/IcePHP/Operation.cpp
+++ b/php/src/IcePHP/Operation.cpp
@@ -50,7 +50,8 @@ class OperationI : public Operation
{
public:
- OperationI(const char*, Ice::OperationMode, Ice::OperationMode, zval*, zval*, zval*, zval* TSRMLS_DC);
+ OperationI(const char*, Ice::OperationMode, Ice::OperationMode, Ice::FormatType, zval*, zval*, zval*, zval*
+ TSRMLS_DC);
~OperationI();
virtual zend_function* function();
@@ -58,6 +59,7 @@ public:
string name; // On-the-wire name.
Ice::OperationMode mode;
Ice::OperationMode sendMode;
+ Ice::FormatType format;
TypeInfoList inParams;
TypeInfoList outParams;
TypeInfoPtr returnType;
@@ -129,6 +131,35 @@ public:
virtual void invoke(INTERNAL_FUNCTION_PARAMETERS);
};
+class UserExceptionReaderFactoryI : public Ice::UserExceptionReaderFactory
+{
+public:
+
+ UserExceptionReaderFactoryI(const CommunicatorInfoPtr& communicator TSRMLS_DC) :
+ _communicator(communicator)
+ {
+#ifdef ZTS
+ this->TSRMLS_C = TSRMLS_C;
+#endif
+ }
+
+ virtual void createAndThrow(const string& id) const
+ {
+ ExceptionInfoPtr info = getExceptionInfo(id TSRMLS_CC);
+ if(info)
+ {
+ throw ExceptionReader(_communicator, info TSRMLS_CC);
+ }
+ }
+
+private:
+
+ const CommunicatorInfoPtr _communicator;
+#if ZTS
+ TSRMLS_D;
+#endif
+};
+
}
//
@@ -160,9 +191,9 @@ IcePHP::ResultCallback::unmarshaled(zval* val, zval*, void* TSRMLS_DC)
//
// OperationI implementation.
//
-IcePHP::OperationI::OperationI(const char* n, Ice::OperationMode m, Ice::OperationMode sm, zval* in, zval* out,
- zval* ret, zval* ex TSRMLS_DC) :
- name(n), mode(m), sendMode(sm), sendsClasses(false), returnsClasses(false), _zendFunction(0)
+IcePHP::OperationI::OperationI(const char* n, Ice::OperationMode m, Ice::OperationMode sm, Ice::FormatType f, zval* in,
+ zval* out, zval* ret, zval* ex TSRMLS_DC) :
+ name(n), mode(m), sendMode(sm), format(f), sendsClasses(false), returnsClasses(false), _zendFunction(0)
{
//
// inParams
@@ -361,6 +392,12 @@ IcePHP::TypedInvocation::prepareRequest(int argc, zval** args, Ice::ByteSeq& byt
// Marshal the in parameters.
//
Ice::OutputStreamPtr os = Ice::createOutputStream(_communicator->getCommunicator());
+ os->startEncapsulation(_prx->ice_getEncodingVersion());
+
+ if(_op->sendsClasses && _op->format != Ice::DefaultFormat)
+ {
+ os->format(_op->format);
+ }
ObjectMap objectMap;
int i = 0;
@@ -380,6 +417,7 @@ IcePHP::TypedInvocation::prepareRequest(int argc, zval** args, Ice::ByteSeq& byt
os->writePendingObjects();
}
+ os->endEncapsulation();
os->finished(bytes);
}
catch(const AbortMarshaling&)
@@ -403,6 +441,16 @@ IcePHP::TypedInvocation::unmarshalResults(int argc, zval** args, zval* ret,
Ice::InputStreamPtr is = Ice::createInputStream(_communicator->getCommunicator(), bytes);
//
+ // Store a pointer to a local SlicedDataUtil object as the stream's closure.
+ // This is necessary to support object unmarshaling (see ObjectReader).
+ //
+ SlicedDataUtil util;
+ assert(!is->closure());
+ is->closure(&util);
+
+ is->startEncapsulation();
+
+ //
// These callbacks collect references to the unmarshaled values. We copy them into
// the argument list *after* any pending objects have been unmarshaled.
//
@@ -433,6 +481,10 @@ IcePHP::TypedInvocation::unmarshalResults(int argc, zval** args, zval* ret,
is->readPendingObjects();
}
+ util.update(TSRMLS_C);
+
+ is->endEncapsulation();
+
int i = static_cast<int>(_op->inParams.size());
for(ResultCallbackList::iterator q = outParamCallbacks.begin(); q != outParamCallbacks.end(); ++q, ++i)
{
@@ -458,71 +510,48 @@ IcePHP::TypedInvocation::unmarshalResults(int argc, zval** args, zval* ret,
zval*
IcePHP::TypedInvocation::unmarshalException(const pair<const Ice::Byte*, const Ice::Byte*>& bytes TSRMLS_DC)
{
- int traceSlicing = -1;
-
Ice::InputStreamPtr is = Ice::createInputStream(_communicator->getCommunicator(), bytes);
- bool usesClasses;
- is->read(usesClasses);
+ //
+ // Store a pointer to a local SlicedDataUtil object as the stream's closure.
+ // This is necessary to support object unmarshaling (see ObjectReader).
+ //
+ SlicedDataUtil util;
+ assert(!is->closure());
+ is->closure(&util);
- string id;
- is->read(id);
- const string origId = id;
+ is->startEncapsulation();
- while(!id.empty())
+ try
{
- ExceptionInfoPtr info = getExceptionInfo(id TSRMLS_CC);
- if(info)
- {
- zval* ex = info->unmarshal(is, _communicator TSRMLS_CC);
- if(ex)
- {
- if(info->usesClasses)
- {
- is->readPendingObjects();
- }
+ Ice::UserExceptionReaderFactoryPtr factory = new UserExceptionReaderFactoryI(_communicator TSRMLS_CC);
+ is->throwException(factory);
+ }
+ catch(const ExceptionReader& r)
+ {
+ is->endEncapsulation();
- if(validateException(info TSRMLS_CC))
- {
- return ex;
- }
- else
- {
- zval_ptr_dtor(&ex);
- Ice::UnknownUserException uue(__FILE__, __LINE__,
- "operation raised undeclared exception `" + id + "'");
- return convertException(uue TSRMLS_CC);
- }
- }
- }
- else
+ zval* ex = r.getException();
+ ExceptionInfoPtr info = r.getInfo();
+
+ if(validateException(info TSRMLS_CC))
{
- if(traceSlicing == -1)
- {
- traceSlicing =
- _communicator->getCommunicator()->getProperties()->getPropertyAsInt("Ice.Trace.Slicing") > 0;
- }
+ util.update(TSRMLS_C);
- if(traceSlicing > 0)
+ Ice::SlicedDataPtr slicedData = r.getSlicedData();
+ if(slicedData)
{
- _communicator->getCommunicator()->getLogger()->trace("Slicing", "unknown exception type `" + id + "'");
+ SlicedDataUtil::setMember(ex, slicedData TSRMLS_CC);
}
- is->skipSlice(); // Slice off what we don't understand.
-
- try
- {
- is->read(id); // Read type id for next slice.
- }
- catch(Ice::UnmarshalOutOfBoundsException& ex)
- {
- //
- // When readString raises this exception it means we've seen the last slice,
- // so we set the reason member to a more helpful message.
- //
- ex.reason = "unknown exception type `" + origId + "'";
- return convertException(ex TSRMLS_CC);
- }
+ return ex;
+ }
+ else
+ {
+ zval_ptr_dtor(&ex);
+ Ice::UnknownUserException uue(__FILE__, __LINE__,
+ "operation raised undeclared exception `" + info->id + "'");
+ return convertException(uue TSRMLS_CC);
}
}
@@ -532,7 +561,7 @@ IcePHP::TypedInvocation::unmarshalException(const pair<const Ice::Byte*, const I
// have a factory for. This means that sender and receiver disagree
// about the Slice definitions they use.
//
- Ice::UnknownUserException uue(__FILE__, __LINE__, "unknown exception type `" + origId + "'");
+ Ice::UnknownUserException uue(__FILE__, __LINE__, "unknown exception");
return convertException(uue TSRMLS_CC);
}
@@ -675,13 +704,14 @@ ZEND_FUNCTION(IcePHP_defineOperation)
int nameLen;
long mode;
long sendMode;
+ long format;
zval* inParams;
zval* outParams;
zval* returnType;
zval* exceptions;
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("oslla!a!o!a!"), &cls, &name, &nameLen, &mode,
- &sendMode, &inParams, &outParams, &returnType, &exceptions) == FAILURE)
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("osllla!a!o!a!"), &cls, &name, &nameLen,
+ &mode, &sendMode, &format, &inParams, &outParams, &returnType, &exceptions) == FAILURE)
{
return;
}
@@ -691,8 +721,8 @@ ZEND_FUNCTION(IcePHP_defineOperation)
assert(c);
OperationIPtr op = new OperationI(name, static_cast<Ice::OperationMode>(mode),
- static_cast<Ice::OperationMode>(sendMode), inParams, outParams, returnType,
- exceptions TSRMLS_CC);
+ static_cast<Ice::OperationMode>(sendMode), static_cast<Ice::FormatType>(format),
+ inParams, outParams, returnType, exceptions TSRMLS_CC);
c->addOperation(name, op);
}
diff --git a/php/src/IcePHP/Proxy.cpp b/php/src/IcePHP/Proxy.cpp
index a8dfcd18c07..f8dcfc88ec2 100644
--- a/php/src/IcePHP/Proxy.cpp
+++ b/php/src/IcePHP/Proxy.cpp
@@ -645,6 +645,62 @@ ZEND_METHOD(Ice_ObjectPrx, ice_secure)
}
}
+ZEND_METHOD(Ice_ObjectPrx, ice_getEncodingVersion)
+{
+ if(ZEND_NUM_ARGS() != 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ ProxyPtr _this = Wrapper<ProxyPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
+
+ try
+ {
+ if(!createEncodingVersion(return_value, _this->proxy->ice_getEncodingVersion() TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
+ }
+}
+
+ZEND_METHOD(Ice_ObjectPrx, ice_encodingVersion)
+{
+ ProxyPtr _this = Wrapper<ProxyPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
+
+ zend_class_entry* cls = idToClass("::Ice::EncodingVersion" TSRMLS_CC);
+ assert(cls);
+
+ zval *zv;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("O"), &zv, cls) == FAILURE)
+ {
+ RETURN_NULL();
+ }
+
+ Ice::EncodingVersion v;
+ if(extractEncodingVersion(zv, v TSRMLS_CC))
+ {
+ try
+ {
+ if(!_this->clone(return_value, _this->proxy->ice_encodingVersion(v) TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
+ }
+ }
+}
+
ZEND_METHOD(Ice_ObjectPrx, ice_isPreferSecure)
{
if(ZEND_NUM_ARGS() != 0)
@@ -1213,6 +1269,27 @@ ZEND_METHOD(Ice_ObjectPrx, ice_getCachedConnection)
}
}
+ZEND_METHOD(Ice_ObjectPrx, ice_flushBatchRequests)
+{
+ if(ZEND_NUM_ARGS() != 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ ProxyPtr _this = Wrapper<ProxyPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
+
+ try
+ {
+ _this->proxy->ice_flushBatchRequests();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
+ }
+}
+
static ClassInfoPtr
lookupClass(const string& id TSRMLS_DC)
{
@@ -1570,6 +1647,8 @@ static zend_function_entry _proxyMethods[] =
ZEND_ME(Ice_ObjectPrx, ice_endpointSelection, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_ObjectPrx, ice_isSecure, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_ObjectPrx, ice_secure, NULL, ZEND_ACC_PUBLIC)
+ ZEND_ME(Ice_ObjectPrx, ice_getEncodingVersion, NULL, ZEND_ACC_PUBLIC)
+ ZEND_ME(Ice_ObjectPrx, ice_encodingVersion, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_ObjectPrx, ice_isPreferSecure, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_ObjectPrx, ice_preferSecure, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_ObjectPrx, ice_getRouter, NULL, ZEND_ACC_PUBLIC)
@@ -1591,6 +1670,7 @@ static zend_function_entry _proxyMethods[] =
ZEND_ME(Ice_ObjectPrx, ice_connectionId, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_ObjectPrx, ice_getConnection, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_ObjectPrx, ice_getCachedConnection, NULL, ZEND_ACC_PUBLIC)
+ ZEND_ME(Ice_ObjectPrx, ice_flushBatchRequests, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_ObjectPrx, ice_uncheckedCast, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_ObjectPrx, ice_checkedCast, NULL, ZEND_ACC_PUBLIC)
{0, 0, 0}
diff --git a/php/src/IcePHP/Types.cpp b/php/src/IcePHP/Types.cpp
index 21f6030009f..b1d392fa3a0 100644
--- a/php/src/IcePHP/Types.cpp
+++ b/php/src/IcePHP/Types.cpp
@@ -14,6 +14,7 @@
#include <IceUtil/OutputUtil.h>
#include <IceUtil/ScopedArray.h>
#include <Slice/PHPUtil.h>
+#include <Ice/SlicedData.h>
using namespace std;
using namespace IcePHP;
@@ -139,6 +140,39 @@ getMostDerived(zend_class_entry* formal, zend_class_entry* cls, const ClassInfoP
return curr;
}
+static ClassInfoPtr
+getClassInfoByClass(zend_class_entry* cls, zend_class_entry* formal TSRMLS_DC)
+{
+ //
+ // See if there's a match in our class name => ClassInfo map.
+ //
+ ClassInfoPtr info = getClassInfoByName(cls->name TSRMLS_CC);
+
+ //
+ // Check the base class, assuming it's compatible with our formal type (if any).
+ //
+ if(!info && cls->parent && (!formal || checkClass(cls->parent, formal)))
+ {
+ info = getClassInfoByClass(cls->parent, formal TSRMLS_CC);
+ }
+
+ //
+ // Check interfaces.
+ //
+ if(!info)
+ {
+ for(zend_uint i = 0; i < cls->num_interfaces && !info; ++i)
+ {
+ if(!formal || checkClass(cls->interfaces[i], formal))
+ {
+ info = getClassInfoByClass(cls->interfaces[i], formal TSRMLS_CC);
+ }
+ }
+ }
+
+ return info;
+}
+
//
// getClassInfoById()
//
@@ -233,6 +267,263 @@ zend_object_handle _h;
}
//
+// SlicedDataUtil implementation
+//
+zend_class_entry* IcePHP::SlicedDataUtil::_slicedDataType = 0;
+zend_class_entry* IcePHP::SlicedDataUtil::_sliceInfoType = 0;
+
+IcePHP::SlicedDataUtil::~SlicedDataUtil()
+{
+ //
+ // Make sure we break any cycles among the objects in preserved slices.
+ //
+ for(set<ObjectReaderPtr>::iterator p = _readers.begin(); p != _readers.end(); ++p)
+ {
+ (*p)->getSlicedData()->clearObjects();
+ }
+}
+
+void
+IcePHP::SlicedDataUtil::add(const ObjectReaderPtr& reader)
+{
+ assert(reader->getSlicedData());
+ _readers.insert(reader);
+}
+
+void
+IcePHP::SlicedDataUtil::update(TSRMLS_D)
+{
+ for(set<ObjectReaderPtr>::iterator p = _readers.begin(); p != _readers.end(); ++p)
+ {
+ setMember((*p)->getObject(), (*p)->getSlicedData() TSRMLS_CC);
+ }
+}
+
+void
+IcePHP::SlicedDataUtil::setMember(zval* obj, const Ice::SlicedDataPtr& slicedData TSRMLS_DC)
+{
+ //
+ // Create a PHP equivalent of the SlicedData object.
+ //
+
+ assert(slicedData);
+
+ if(!_slicedDataType)
+ {
+ _slicedDataType = idToClass("::Ice::SlicedData" TSRMLS_CC);
+ assert(_slicedDataType);
+ }
+ if(!_sliceInfoType)
+ {
+ _sliceInfoType = idToClass("::Ice::SliceInfo" TSRMLS_CC);
+ assert(_sliceInfoType);
+ }
+
+ zval* sd;
+ MAKE_STD_ZVAL(sd);
+ AutoDestroy sdDestroyer(sd);
+
+ if(object_init_ex(sd, _slicedDataType) != SUCCESS)
+ {
+ throw AbortMarshaling();
+ }
+
+ zval* slices;
+ MAKE_STD_ZVAL(slices);
+ array_init(slices);
+ AutoDestroy slicesDestroyer(slices);
+
+ if(add_property_zval(sd, STRCAST("slices"), slices) != SUCCESS)
+ {
+ throw AbortMarshaling();
+ }
+
+ //
+ // Translate each SliceInfo object into its PHP equivalent.
+ //
+ for(vector<Ice::SliceInfoPtr>::const_iterator p = slicedData->slices.begin(); p != slicedData->slices.end(); ++p)
+ {
+ zval* slice;
+ MAKE_STD_ZVAL(slice);
+ AutoDestroy sliceDestroyer(slice);
+
+ if(object_init_ex(slice, _sliceInfoType) != SUCCESS)
+ {
+ throw AbortMarshaling();
+ }
+
+ add_next_index_zval(slices, slice); // Steals a reference.
+ Z_ADDREF_P(slice);
+
+ //
+ // typeId
+ //
+ zval* typeId;
+ MAKE_STD_ZVAL(typeId);
+ AutoDestroy typeIdDestroyer(typeId);
+ ZVAL_STRINGL(typeId, STRCAST((*p)->typeId.c_str()), (*p)->typeId.size(), 1);
+ if(add_property_zval(slice, STRCAST("typeId"), typeId) != SUCCESS)
+ {
+ throw AbortMarshaling();
+ }
+
+ //
+ // bytes
+ //
+ zval* bytes;
+ MAKE_STD_ZVAL(bytes);
+ array_init(bytes);
+ AutoDestroy bytesDestroyer(bytes);
+ for(vector<Ice::Byte>::const_iterator q = (*p)->bytes.begin(); q != (*p)->bytes.end(); ++q)
+ {
+ add_next_index_long(bytes, *q & 0xff);
+ }
+ if(add_property_zval(slice, STRCAST("bytes"), bytes) != SUCCESS)
+ {
+ throw AbortMarshaling();
+ }
+
+ //
+ // objects
+ //
+ zval* objects;
+ MAKE_STD_ZVAL(objects);
+ array_init(objects);
+ AutoDestroy objectsDestroyer(objects);
+ if(add_property_zval(slice, STRCAST("objects"), objects) != SUCCESS)
+ {
+ throw AbortMarshaling();
+ }
+
+ for(vector<Ice::ObjectPtr>::const_iterator q = (*p)->objects.begin(); q != (*p)->objects.end(); ++q)
+ {
+ //
+ // Each element in the objects list is an instance of ObjectReader that wraps a PHP object.
+ //
+ assert(*q);
+ ObjectReaderPtr r = ObjectReaderPtr::dynamicCast(*q);
+ assert(r);
+ zval* o = r->getObject();
+ assert(Z_TYPE_P(o) == IS_OBJECT); // Should be non-nil.
+ add_next_index_zval(objects, o); // Steals a reference.
+ Z_ADDREF_P(o);
+ }
+ }
+
+ if(add_property_zval(obj, STRCAST("_ice_slicedData"), sd) != SUCCESS)
+ {
+ throw AbortMarshaling();
+ }
+}
+
+//
+// Instances of preserved class and exception types may have a data member
+// named _ice_slicedData which is an instance of the PHP class Ice_SlicedData.
+//
+Ice::SlicedDataPtr
+IcePHP::SlicedDataUtil::getMember(zval* obj, ObjectMap* objectMap TSRMLS_DC)
+{
+ Ice::SlicedDataPtr slicedData;
+
+ string name = "_ice_slicedData";
+ void* data;
+ if(zend_hash_find(Z_OBJPROP_P(obj), STRCAST(name.c_str()), name.size() + 1, &data) == SUCCESS)
+ {
+ zval* sd = *(reinterpret_cast<zval**>(data));
+
+ if(Z_TYPE_P(sd) != IS_NULL)
+ {
+ int status;
+
+ //
+ // The "slices" member is an array of Ice_SliceInfo objects.
+ //
+ status = zend_hash_find(Z_OBJPROP_P(sd), STRCAST("slices"), sizeof("slices"), &data);
+ assert(status == SUCCESS);
+ zval* sl = *(reinterpret_cast<zval**>(data));
+ assert(Z_TYPE_P(sl) == IS_ARRAY);
+
+ Ice::SliceInfoSeq slices;
+
+ HashTable* arr = Z_ARRVAL_P(sl);
+ assert(arr);
+ HashPosition pos;
+ zend_hash_internal_pointer_reset_ex(arr, &pos);
+
+ while(zend_hash_get_current_data_ex(arr, &data, &pos) != FAILURE)
+ {
+ zval* s = *(reinterpret_cast<zval**>(data));
+ assert(Z_OBJCE_P(s) == _sliceInfoType);
+
+ Ice::SliceInfoPtr info = new Ice::SliceInfo;
+
+ status = zend_hash_find(Z_OBJPROP_P(s), STRCAST("typeId"), sizeof("typeId"), &data);
+ assert(status == SUCCESS);
+ zval* typeId = *(reinterpret_cast<zval**>(data));
+ assert(Z_TYPE_P(typeId) == IS_STRING);
+ info->typeId = string(Z_STRVAL_P(typeId), Z_STRLEN_P(typeId));
+
+ status = zend_hash_find(Z_OBJPROP_P(s), STRCAST("bytes"), sizeof("bytes"), &data);
+ assert(status == SUCCESS);
+ zval* bytes = *(reinterpret_cast<zval**>(data));
+ assert(Z_TYPE_P(bytes) == IS_ARRAY);
+ HashTable* barr = Z_ARRVAL_P(bytes);
+ HashPosition bpos;
+ zend_hash_internal_pointer_reset_ex(barr, &bpos);
+ info->bytes.resize(zend_hash_num_elements(barr));
+
+ vector<Ice::Byte>::size_type i = 0;
+ while(zend_hash_get_current_data_ex(barr, &data, &bpos) != FAILURE)
+ {
+ zval* e = *(reinterpret_cast<zval**>(data));
+ long l = Z_LVAL_P(e);
+ assert(l >= 0 && l <= 255);
+ info->bytes[i++] = static_cast<Ice::Byte>(l);
+ zend_hash_move_forward_ex(barr, &bpos);
+ }
+
+ status = zend_hash_find(Z_OBJPROP_P(s), STRCAST("objects"), sizeof("objects"), &data);
+ assert(status == SUCCESS);
+ zval* objects = *(reinterpret_cast<zval**>(data));
+ assert(Z_TYPE_P(objects) == IS_ARRAY);
+ HashTable* oarr = Z_ARRVAL_P(objects);
+ HashPosition opos;
+ zend_hash_internal_pointer_reset_ex(oarr, &opos);
+
+ while(zend_hash_get_current_data_ex(oarr, &data, &opos) != FAILURE)
+ {
+ zval* o = *(reinterpret_cast<zval**>(data));
+ assert(Z_TYPE_P(o) == IS_OBJECT);
+
+ Ice::ObjectPtr writer;
+
+ ObjectMap::iterator i = objectMap->find(Z_OBJ_HANDLE_P(o));
+ if(i == objectMap->end())
+ {
+ writer = new ObjectWriter(o, objectMap, 0 TSRMLS_CC);
+ objectMap->insert(ObjectMap::value_type(Z_OBJ_HANDLE_P(o), writer));
+ }
+ else
+ {
+ writer = i->second;
+ }
+
+ info->objects.push_back(writer);
+ zend_hash_move_forward_ex(oarr, &opos);
+ }
+
+ slices.push_back(info);
+ zend_hash_move_forward_ex(arr, &pos);
+ }
+
+ slicedData = new Ice::SlicedData(slices);
+ }
+ }
+
+ return slicedData;
+}
+
+//
// UnmarshalCallback implementation.
//
IcePHP::UnmarshalCallback::~UnmarshalCallback()
@@ -1770,13 +2061,7 @@ IcePHP::ClassInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap*
ObjectMap::iterator q = objectMap->find(Z_OBJ_HANDLE_P(zv));
if(q == objectMap->end())
{
- //
- // Determine the most-derived Slice type implemented by this object by scanning its
- // inheritance hierarchy until we find a class or interface that we recognize.
- //
- ClassInfoPtr info = getMostDerived(zce, Z_OBJCE_P(zv), 0 TSRMLS_CC);
- assert(info);
- writer = new ObjectWriter(info, zv, objectMap TSRMLS_CC);
+ writer = new ObjectWriter(zv, objectMap, this TSRMLS_CC);
objectMap->insert(ObjectMap::value_type(Z_OBJ_HANDLE_P(zv), writer));
}
else
@@ -2045,19 +2330,29 @@ IcePHP::ProxyInfo::destroy()
//
// ObjectWriter implementation.
//
-IcePHP::ObjectWriter::ObjectWriter(const ClassInfoPtr& info, zval* object, ObjectMap* objectMap TSRMLS_DC) :
- _info(info), _object(object), _map(objectMap)
+IcePHP::ObjectWriter::ObjectWriter(zval* object, ObjectMap* objectMap, const ClassInfoPtr& formal TSRMLS_DC) :
+ _object(object), _map(objectMap)
{
#ifdef ZTS
this->TSRMLS_C = TSRMLS_C;
#endif
- Z_OBJ_HT_P(_object)->add_ref(_object TSRMLS_CC);
+ Z_ADDREF_P(_object);
+
+ //
+ // We need to determine the most-derived Slice type supported by this object.
+ // This is typically a Slice class, but it can also be an interface.
+ //
+ // The caller may have provided a ClassInfo representing the formal type, in
+ // which case we ensure that the actual type is compatible with the formal type.
+ //
+ _info = getClassInfoByClass(Z_OBJCE_P(object), formal ? formal->zce : 0 TSRMLS_CC);
+ assert(_info);
}
IcePHP::ObjectWriter::~ObjectWriter()
{
- Z_OBJ_HT_P(_object)->del_ref(_object TSRMLS_CC);
+ zval_ptr_dtor(&_object);
}
void
@@ -2076,12 +2371,24 @@ IcePHP::ObjectWriter::ice_preMarshal()
void
IcePHP::ObjectWriter::write(const Ice::OutputStreamPtr& os) const
{
+ Ice::SlicedDataPtr slicedData;
+
+ if(_info->preserve)
+ {
+ //
+ // Retrieve the SlicedData object that we stored as a hidden member of the PHP object.
+ //
+ slicedData = SlicedDataUtil::getMember(_object, const_cast<ObjectMap*>(_map) TSRMLS_CC);
+ }
+
+ os->startObject(slicedData);
+
ClassInfoPtr info = _info;
while(info && info->id != Ice::Object::ice_staticId())
{
- os->writeTypeId(info->id);
-
- os->startSlice();
+ assert(info->base); // All classes have the Ice::Object base type.
+ const bool lastSlice = info->base->id == Ice::Object::ice_staticId();
+ os->startSlice(info->id, lastSlice);
for(DataMemberList::iterator q = info->members.begin(); q != info->members.end(); ++q)
{
DataMemberPtr member = *q;
@@ -2107,13 +2414,7 @@ IcePHP::ObjectWriter::write(const Ice::OutputStreamPtr& os) const
info = info->base;
}
- //
- // Marshal the Ice::Object slice.
- //
- os->writeTypeId(Ice::Object::ice_staticId());
- os->startSlice();
- os->writeSize(0); // For compatibility with the old AFM.
- os->endSlice();
+ os->endObject();
}
//
@@ -2148,19 +2449,16 @@ IcePHP::ObjectReader::ice_postUnmarshal()
}
void
-IcePHP::ObjectReader::read(const Ice::InputStreamPtr& is, bool rid)
+IcePHP::ObjectReader::read(const Ice::InputStreamPtr& is)
{
+ is->startObject();
+
//
// Unmarshal the slices of a user-defined class.
//
ClassInfoPtr info = _info;
while(info && info->id != Ice::Object::ice_staticId())
{
- if(rid)
- {
- is->readTypeId();
- }
-
is->startSlice();
for(DataMemberList::iterator p = info->members.begin(); p != info->members.end(); ++p)
{
@@ -2169,27 +2467,17 @@ IcePHP::ObjectReader::read(const Ice::InputStreamPtr& is, bool rid)
}
is->endSlice();
- rid = true;
-
info = info->base;
}
- //
- // Unmarshal the Ice::Object slice.
- //
- if(rid)
- {
- is->readTypeId();
- }
+ _slicedData = is->endObject(_info->preserve);
- is->startSlice();
- // For compatibility with the old AFM.
- Ice::Int sz = is->readSize();
- if(sz != 0)
+ if(_slicedData)
{
- throw Ice::MarshalException(__FILE__, __LINE__);
+ SlicedDataUtil* util = reinterpret_cast<SlicedDataUtil*>(is->closure());
+ assert(util);
+ util->add(this);
}
- is->endSlice();
}
ClassInfoPtr
@@ -2204,6 +2492,12 @@ IcePHP::ObjectReader::getObject() const
return _object;
}
+Ice::SlicedDataPtr
+IcePHP::ObjectReader::getSlicedData() const
+{
+ return _slicedData;
+}
+
//
// ReadObjectCallback implementation.
//
@@ -2297,11 +2591,6 @@ IcePHP::ExceptionInfo::unmarshal(const Ice::InputStreamPtr& is, const Communicat
is->endSlice();
info = info->base;
- if(info)
- {
- string id;
- is->read(id); // Read the ID of the next slice.
- }
}
return destroy.release();
@@ -2378,6 +2667,81 @@ IcePHP::ExceptionInfo::isA(const string& typeId) const
return false;
}
+//
+// ExceptionReader implementation.
+//
+IcePHP::ExceptionReader::ExceptionReader(const CommunicatorInfoPtr& communicatorInfo, const ExceptionInfoPtr& info
+ TSRMLS_DC) :
+ Ice::UserExceptionReader(communicatorInfo->getCommunicator()), _communicatorInfo(communicatorInfo), _info(info)
+{
+#ifdef ZTS
+ this->TSRMLS_C = TSRMLS_C;
+#endif
+}
+
+IcePHP::ExceptionReader::~ExceptionReader()
+ throw()
+{
+}
+
+void
+IcePHP::ExceptionReader::read(const Ice::InputStreamPtr& is) const
+{
+ is->startException();
+
+ const_cast<zval*&>(_ex) = _info->unmarshal(is, _communicatorInfo TSRMLS_CC);
+
+ const_cast<Ice::SlicedDataPtr&>(_slicedData) = is->endException(_info->preserve);
+}
+
+bool
+IcePHP::ExceptionReader::usesClasses() const
+{
+ return _info->usesClasses;
+}
+
+void
+IcePHP::ExceptionReader::usesClasses(bool)
+{
+}
+
+string
+IcePHP::ExceptionReader::ice_name() const
+{
+ return _info->id;
+}
+
+Ice::Exception*
+IcePHP::ExceptionReader::ice_clone() const
+{
+ assert(false);
+ return 0;
+}
+
+void
+IcePHP::ExceptionReader::ice_throw() const
+{
+ throw *this;
+}
+
+ExceptionInfoPtr
+IcePHP::ExceptionReader::getInfo() const
+{
+ return _info;
+}
+
+zval*
+IcePHP::ExceptionReader::getException() const
+{
+ return _ex;
+}
+
+Ice::SlicedDataPtr
+IcePHP::ExceptionReader::getSlicedData() const
+{
+ return _slicedData;
+}
+
#ifdef _WIN32
extern "C"
#endif
@@ -2631,12 +2995,13 @@ ZEND_FUNCTION(IcePHP_defineClass)
char* name;
int nameLen;
zend_bool isAbstract;
+ zend_bool preserve;
zval* base;
zval* interfaces;
zval* members;
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("ssbo!a!a!"), &id, &idLen, &name, &nameLen,
- &isAbstract, &base, &interfaces, &members) == FAILURE)
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("ssbbo!a!a!"), &id, &idLen, &name, &nameLen,
+ &isAbstract, &preserve, &base, &interfaces, &members) == FAILURE)
{
return;
}
@@ -2653,6 +3018,7 @@ ZEND_FUNCTION(IcePHP_defineClass)
addClassInfoByName(type TSRMLS_CC);
type->isAbstract = isAbstract ? true : false;
+ type->preserve = preserve ? true : false;
if(base)
{
TypeInfoPtr p = Wrapper<TypeInfoPtr>::value(base TSRMLS_CC);
@@ -2746,11 +3112,12 @@ ZEND_FUNCTION(IcePHP_defineException)
int idLen;
char* name;
int nameLen;
+ zend_bool preserve;
zval* base;
zval* members;
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("sso!a!"), &id, &idLen, &name, &nameLen,
- &base, &members) == FAILURE)
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("ssbo!a!"), &id, &idLen, &name, &nameLen,
+ &preserve, &base, &members) == FAILURE)
{
return;
}
@@ -2758,6 +3125,7 @@ ZEND_FUNCTION(IcePHP_defineException)
ExceptionInfoPtr ex = new ExceptionInfo();
ex->id = id;
ex->name = name;
+ ex->preserve = preserve ? true : false;
if(base)
{
ex->base = Wrapper<ExceptionInfoPtr>::value(base TSRMLS_CC);
diff --git a/php/src/IcePHP/Types.h b/php/src/IcePHP/Types.h
index 14ce1d0ec6d..917ad19c89b 100644
--- a/php/src/IcePHP/Types.h
+++ b/php/src/IcePHP/Types.h
@@ -45,6 +45,33 @@ class AbortMarshaling
typedef std::map<unsigned int, Ice::ObjectPtr> ObjectMap;
+class ObjectReader;
+typedef IceUtil::Handle<ObjectReader> ObjectReaderPtr;
+
+//
+// This class keeps track of PHP objects (instances of Slice classes
+// and exceptions) that have preserved slices.
+//
+class SlicedDataUtil
+{
+public:
+
+ ~SlicedDataUtil();
+
+ void add(const ObjectReaderPtr&);
+
+ void update(TSRMLS_D);
+
+ static void setMember(zval*, const Ice::SlicedDataPtr& TSRMLS_DC);
+ static Ice::SlicedDataPtr getMember(zval*, ObjectMap* TSRMLS_DC);
+
+private:
+
+ std::set<ObjectReaderPtr> _readers;
+ static zend_class_entry* _slicedDataType;
+ static zend_class_entry* _sliceInfoType;
+};
+
struct PrintObjectHistory
{
int index;
@@ -329,6 +356,7 @@ public:
std::string id;
std::string name; // PHP class name
bool isAbstract;
+ bool preserve;
ClassInfoPtr base;
ClassInfoList interfaces;
DataMemberList members;
@@ -379,6 +407,7 @@ public:
std::string id;
std::string name; // PHP class name
+ bool preserve;
ExceptionInfoPtr base;
DataMemberList members;
bool usesClasses;
@@ -400,7 +429,7 @@ class ObjectWriter : public Ice::ObjectWriter
{
public:
- ObjectWriter(const ClassInfoPtr&, zval*, ObjectMap* TSRMLS_DC);
+ ObjectWriter(zval*, ObjectMap*, const ClassInfoPtr& TSRMLS_DC);
~ObjectWriter();
virtual void ice_preMarshal();
@@ -409,9 +438,9 @@ public:
private:
- ClassInfoPtr _info;
zval* _object;
ObjectMap* _map;
+ ClassInfoPtr _info;
#if ZTS
TSRMLS_D;
#endif
@@ -429,22 +458,59 @@ public:
virtual void ice_postUnmarshal();
- virtual void read(const Ice::InputStreamPtr&, bool);
+ virtual void read(const Ice::InputStreamPtr&);
virtual ClassInfoPtr getInfo() const;
zval* getObject() const;
+ Ice::SlicedDataPtr getSlicedData() const;
+
private:
zval* _object;
ClassInfoPtr _info;
CommunicatorInfoPtr _communicator;
+ Ice::SlicedDataPtr _slicedData;
+#if ZTS
+ TSRMLS_D;
+#endif
+};
+
+//
+// ExceptionReader creates a PHP user exception and unmarshals it.
+//
+class ExceptionReader : public Ice::UserExceptionReader
+{
+public:
+
+ ExceptionReader(const CommunicatorInfoPtr&, const ExceptionInfoPtr& TSRMLS_DC);
+ ~ExceptionReader() throw();
+
+ virtual void read(const Ice::InputStreamPtr&) const;
+ virtual bool usesClasses() const;
+ virtual void usesClasses(bool);
+
+ virtual std::string ice_name() const;
+ virtual Ice::Exception* ice_clone() const;
+ virtual void ice_throw() const;
+
+ ExceptionInfoPtr getInfo() const;
+
+ zval* getException() const;
+
+ Ice::SlicedDataPtr getSlicedData() const;
+
+private:
+
+ CommunicatorInfoPtr _communicatorInfo;
+ ExceptionInfoPtr _info;
+ zval* _ex;
+ Ice::SlicedDataPtr _slicedData;
#if ZTS
TSRMLS_D;
#endif
};
-typedef IceUtil::Handle<ObjectReader> ObjectReaderPtr;
} // End of namespace IcePHP
diff --git a/php/src/IcePHP/Util.cpp b/php/src/IcePHP/Util.cpp
index 60b52ac15a0..2bd1875bce5 100644
--- a/php/src/IcePHP/Util.cpp
+++ b/php/src/IcePHP/Util.cpp
@@ -17,6 +17,169 @@ using namespace std;
using namespace IcePHP;
using namespace Slice::PHP;
+namespace
+{
+
+bool
+getMember(zval* zv, const string& name, zval** member, int type, bool required TSRMLS_DC)
+{
+ *member = 0;
+
+ void* data = 0;
+ if(zend_hash_find(Z_OBJPROP_P(zv), STRCAST(name.c_str()), name.size() + 1, &data) == FAILURE)
+ {
+ if(required)
+ {
+ invalidArgument("object does not contain member `%s'" TSRMLS_CC, name.c_str());
+ return false;
+ }
+ }
+
+ if(data)
+ {
+ zval** val = reinterpret_cast<zval**>(data);
+
+ if(Z_TYPE_PP(val) != type)
+ {
+ string expected = zendTypeToString(type);
+ string actual = zendTypeToString(Z_TYPE_PP(val));
+ invalidArgument("expected value of type %s for member `%s' but received %s" TSRMLS_CC, expected.c_str(),
+ name.c_str(), actual.c_str());
+ return false;
+ }
+
+ *member = *val;
+ }
+
+ return true;
+}
+
+void
+setStringMember(zval* obj, const string& name, const string& val TSRMLS_DC)
+{
+ zend_class_entry* cls = Z_OBJCE_P(obj);
+ assert(cls);
+ zend_update_property_stringl(cls, obj, const_cast<char*>(name.c_str()), static_cast<int>(name.size()),
+ const_cast<char*>(val.c_str()), static_cast<int>(val.size()) TSRMLS_CC);
+}
+
+template<typename T, const char* PT>
+bool
+getVersion(zval* zv, T& v TSRMLS_DC)
+{
+ if(Z_TYPE_P(zv) != IS_OBJECT)
+ {
+ invalidArgument("value does not contain an object" TSRMLS_CC);
+ return false;
+ }
+
+ zend_class_entry* cls = idToClass(PT TSRMLS_CC);
+ assert(cls);
+
+ zend_class_entry* ce = Z_OBJCE_P(zv);
+ if(ce != cls)
+ {
+ invalidArgument("expected an instance of %s" TSRMLS_CC, ce->name);
+ return false;
+ }
+
+ zval* majorVal;
+ if(!getMember(zv, "major", &majorVal, IS_LONG, true TSRMLS_CC))
+ {
+ return false;
+ }
+
+ zval* minorVal;
+ if(!getMember(zv, "minor", &minorVal, IS_LONG, true TSRMLS_CC))
+ {
+ return false;
+ }
+
+ long m;
+ m = Z_LVAL_P(majorVal);
+ if(m < 0 || m > 255)
+ {
+ invalidArgument("version major must be a value between 0 and 255" TSRMLS_CC);
+ return false;
+ }
+ v.major = m;
+
+ m = Z_LVAL_P(minorVal);
+ if(m < 0 || m > 255)
+ {
+ invalidArgument("version minor must be a value between 0 and 255" TSRMLS_CC);
+ return false;
+ }
+ v.minor = m;
+
+ return true;
+}
+
+template<typename T, const char* PT>
+bool
+createVersion(zval* zv, const T& version TSRMLS_DC)
+{
+ zend_class_entry* cls = idToClass(PT TSRMLS_CC);
+ assert(cls);
+
+ if(object_init_ex(zv, cls) != SUCCESS)
+ {
+ runtimeError("unable to initialize %s" TSRMLS_CC, cls->name);
+ return false;
+ }
+
+ zend_update_property_long(cls, zv, const_cast<char*>("major"), sizeof("major") - 1, version.major TSRMLS_CC);
+ zend_update_property_long(cls, zv, const_cast<char*>("minor"), sizeof("minor") - 1, version.minor TSRMLS_CC);
+
+ return true;
+}
+
+template<typename T, const char* PT>
+bool
+versionToString(zval* zv, zval* s TSRMLS_DC)
+{
+ T v;
+ if(!getVersion<T, PT>(zv, v TSRMLS_CC))
+ {
+ return false;
+ }
+
+ try
+ {
+ string str = IceInternal::versionToString<T>(v);
+ ZVAL_STRINGL(s, STRCAST(str.c_str()), str.length(), 1);
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ return false;
+ }
+
+ return true;
+}
+
+template<typename T, const char* PT>
+bool
+stringToVersion(const string& s, zval* zv TSRMLS_DC)
+{
+ try
+ {
+ T v = IceInternal::stringToVersion<T>(s);
+ return createVersion<T, PT>(zv, v TSRMLS_CC);
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ }
+
+ return false;
+}
+
+char Ice_ProtocolVersion[] = "::Ice::ProtocolVersion";
+char Ice_EncodingVersion[] = "::Ice::EncodingVersion";
+
+}
+
#if PHP_VERSION_ID < 50400
#ifdef _WIN32
extern "C"
@@ -103,10 +266,8 @@ IcePHP::createIdentity(zval* zv, const Ice::Identity& id TSRMLS_DC)
return false;
}
- zend_update_property_string(cls, zv, const_cast<char*>("name"), sizeof("name") - 1, STRCAST(id.name.c_str())
- TSRMLS_CC);
- zend_update_property_string(cls, zv, const_cast<char*>("category"), sizeof("category") - 1,
- STRCAST(id.category.c_str()) TSRMLS_CC);
+ setStringMember(zv, "name", id.name TSRMLS_CC);
+ setStringMember(zv, "category", id.category TSRMLS_CC);
return true;
}
@@ -133,35 +294,19 @@ IcePHP::extractIdentity(zval* zv, Ice::Identity& id TSRMLS_DC)
//
// Category is optional, but name is required.
//
- void* categoryData = 0;
- void* nameData;
- if(zend_hash_find(Z_OBJPROP_P(zv), STRCAST("name"), sizeof("name"), &nameData) == FAILURE)
- {
- invalidArgument("identity value does not contain member `name'" TSRMLS_CC);
- return false;
- }
- zend_hash_find(Z_OBJPROP_P(zv), STRCAST("category"), sizeof("category"), &categoryData);
- zval** categoryVal = reinterpret_cast<zval**>(categoryData);
- zval** nameVal = reinterpret_cast<zval**>(nameData);
+ zval* categoryVal;
+ zval* nameVal;
- if(Z_TYPE_PP(nameVal) != IS_STRING)
+ if(!getMember(zv, "category", &categoryVal, IS_STRING, false TSRMLS_CC) ||
+ !getMember(zv, "name", &nameVal, IS_STRING, true TSRMLS_CC))
{
- string s = zendTypeToString(Z_TYPE_PP(nameVal));
- invalidArgument("expected a string value for identity member `name' but received %s" TSRMLS_CC, s.c_str());
return false;
}
- if(categoryVal && Z_TYPE_PP(categoryVal) != IS_STRING && Z_TYPE_PP(categoryVal) != IS_NULL)
+ id.name = Z_STRVAL_P(nameVal);
+ if(categoryVal)
{
- string s = zendTypeToString(Z_TYPE_PP(categoryVal));
- invalidArgument("expected a string value for identity member `category' but received %s" TSRMLS_CC, s.c_str());
- return false;
- }
-
- id.name = Z_STRVAL_PP(nameVal);
- if(categoryVal && Z_TYPE_PP(categoryVal) == IS_STRING)
- {
- id.category = Z_STRVAL_PP(categoryVal);
+ id.category = Z_STRVAL_P(categoryVal);
}
else
{
@@ -286,13 +431,22 @@ IcePHP::extractStringArray(zval* zv, Ice::StringSeq& seq TSRMLS_DC)
return true;
}
-static void
-setStringMember(zval* obj, const string& name, const string& val TSRMLS_DC)
+bool
+IcePHP::createProtocolVersion(zval* zv, const Ice::ProtocolVersion& v TSRMLS_DC)
{
- zend_class_entry* cls = Z_OBJCE_P(obj);
- assert(cls);
- zend_update_property_stringl(cls, obj, const_cast<char*>(name.c_str()), static_cast<int>(name.size()),
- const_cast<char*>(val.c_str()), static_cast<int>(val.size()) TSRMLS_CC);
+ return createVersion<Ice::ProtocolVersion, Ice_ProtocolVersion>(zv, v TSRMLS_CC);
+}
+
+bool
+IcePHP::createEncodingVersion(zval* zv, const Ice::EncodingVersion& v TSRMLS_DC)
+{
+ return createVersion<Ice::EncodingVersion, Ice_EncodingVersion>(zv, v TSRMLS_CC);
+}
+
+bool
+IcePHP::extractEncodingVersion(zval* zv, Ice::EncodingVersion& v TSRMLS_DC)
+{
+ return getVersion<Ice::EncodingVersion, Ice_EncodingVersion>(zv, v TSRMLS_CC);
}
static bool
@@ -368,6 +522,7 @@ convertLocalException(const Ice::LocalException& ex, zval* zex TSRMLS_DC)
return false;
}
zend_update_property(cls, zex, const_cast<char*>("id"), sizeof("id") - 1, id TSRMLS_CC);
+ zval_ptr_dtor(&id);
}
catch(const Ice::RequestFailedException& e)
{
@@ -379,6 +534,7 @@ convertLocalException(const Ice::LocalException& ex, zval* zex TSRMLS_DC)
return false;
}
zend_update_property(cls, zex, const_cast<char*>("id"), sizeof("id") - 1, id TSRMLS_CC);
+ zval_ptr_dtor(&id);
setStringMember(zex, "facet", e.facet TSRMLS_CC);
setStringMember(zex, "operation", e.operation TSRMLS_CC);
}
@@ -398,21 +554,45 @@ convertLocalException(const Ice::LocalException& ex, zval* zex TSRMLS_DC)
}
catch(const Ice::UnsupportedProtocolException& e)
{
- zend_update_property_long(cls, zex, const_cast<char*>("badMajor"), sizeof("badMajor") - 1, e.badMajor
- TSRMLS_CC);
- zend_update_property_long(cls, zex, const_cast<char*>("badMinor"), sizeof("badMinor") - 1, e.badMinor
- TSRMLS_CC);
- zend_update_property_long(cls, zex, const_cast<char*>("major"), sizeof("major") - 1, e.major TSRMLS_CC);
- zend_update_property_long(cls, zex, const_cast<char*>("minor"), sizeof("minor") - 1, e.minor TSRMLS_CC);
+ zval* v;
+ MAKE_STD_ZVAL(v);
+ if(!createProtocolVersion(v, e.bad TSRMLS_CC))
+ {
+ zval_ptr_dtor(&v);
+ return false;
+ }
+ zend_update_property(cls, zex, const_cast<char*>("bad"), sizeof("bad") - 1, v TSRMLS_CC);
+ zval_ptr_dtor(&v);
+
+ MAKE_STD_ZVAL(v);
+ if(!createProtocolVersion(v, e.supported TSRMLS_CC))
+ {
+ zval_ptr_dtor(&v);
+ return false;
+ }
+ zend_update_property(cls, zex, const_cast<char*>("supported"), sizeof("supported") - 1, v TSRMLS_CC);
+ zval_ptr_dtor(&v);
}
catch(const Ice::UnsupportedEncodingException& e)
{
- zend_update_property_long(cls, zex, const_cast<char*>("badMajor"), sizeof("badMajor") - 1, e.badMajor
- TSRMLS_CC);
- zend_update_property_long(cls, zex, const_cast<char*>("badMinor"), sizeof("badMinor") - 1, e.badMinor
- TSRMLS_CC);
- zend_update_property_long(cls, zex, const_cast<char*>("major"), sizeof("major") - 1, e.major TSRMLS_CC);
- zend_update_property_long(cls, zex, const_cast<char*>("minor"), sizeof("minor") - 1, e.minor TSRMLS_CC);
+ zval* v;
+ MAKE_STD_ZVAL(v);
+ if(!createEncodingVersion(v, e.bad TSRMLS_CC))
+ {
+ zval_ptr_dtor(&v);
+ return false;
+ }
+ zend_update_property(cls, zex, const_cast<char*>("bad"), sizeof("bad") - 1, v TSRMLS_CC);
+ zval_ptr_dtor(&v);
+
+ MAKE_STD_ZVAL(v);
+ if(!createEncodingVersion(v, e.supported TSRMLS_CC))
+ {
+ zval_ptr_dtor(&v);
+ return false;
+ }
+ zend_update_property(cls, zex, const_cast<char*>("supported"), sizeof("supported") - 1, v TSRMLS_CC);
+ zval_ptr_dtor(&v);
}
catch(const Ice::NoObjectFactoryException& e)
{
@@ -746,3 +926,108 @@ ZEND_FUNCTION(Ice_generateUUID)
string uuid = IceUtil::generateUUID();
RETURN_STRINGL(STRCAST(uuid.c_str()), uuid.size(), 1);
}
+
+ZEND_FUNCTION(Ice_currentProtocol)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ if(!createProtocolVersion(return_value, Ice::currentProtocol TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_currentProtocolEncoding)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ if(!createEncodingVersion(return_value, Ice::currentProtocolEncoding TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_currentEncoding)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ if(!createEncodingVersion(return_value, Ice::currentEncoding TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_protocolVersionToString)
+{
+ zend_class_entry* versionClass = idToClass(Ice_ProtocolVersion TSRMLS_CC);
+ assert(versionClass);
+
+ zval* zv;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("O"), &zv, versionClass) != SUCCESS)
+ {
+ RETURN_NULL();
+ }
+
+ if(!versionToString<Ice::ProtocolVersion, Ice_ProtocolVersion>(zv, return_value TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_stringToProtocolVersion)
+{
+ char* str;
+ int strLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &str, &strLen) != SUCCESS)
+ {
+ RETURN_NULL();
+ }
+ string s(str, strLen);
+
+ if(!stringToVersion<Ice::ProtocolVersion, Ice_ProtocolVersion>(s, return_value TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_encodingVersionToString)
+{
+ zend_class_entry* versionClass = idToClass(Ice_EncodingVersion TSRMLS_CC);
+ assert(versionClass);
+
+ zval* zv;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("O"), &zv, versionClass) != SUCCESS)
+ {
+ RETURN_NULL();
+ }
+
+ if(!versionToString<Ice::EncodingVersion, Ice_EncodingVersion>(zv, return_value TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_stringToEncodingVersion)
+{
+ char* str;
+ int strLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &str, &strLen) != SUCCESS)
+ {
+ RETURN_NULL();
+ }
+ string s(str, strLen);
+
+ if(!stringToVersion<Ice::EncodingVersion, Ice_EncodingVersion>(s, return_value TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
diff --git a/php/src/IcePHP/Util.h b/php/src/IcePHP/Util.h
index 8dde23d9969..e73bcfaf296 100644
--- a/php/src/IcePHP/Util.h
+++ b/php/src/IcePHP/Util.h
@@ -20,6 +20,13 @@ extern "C"
ZEND_FUNCTION(Ice_stringVersion);
ZEND_FUNCTION(Ice_intVersion);
ZEND_FUNCTION(Ice_generateUUID);
+ZEND_FUNCTION(Ice_currentProtocol);
+ZEND_FUNCTION(Ice_currentProtocolEncoding);
+ZEND_FUNCTION(Ice_currentEncoding);
+ZEND_FUNCTION(Ice_protocolVersionToString);
+ZEND_FUNCTION(Ice_stringToProtocolVersion);
+ZEND_FUNCTION(Ice_encodingVersionToString);
+ZEND_FUNCTION(Ice_stringToEncodingVersion);
}
namespace IcePHP
@@ -73,6 +80,21 @@ bool createStringArray(zval*, const Ice::StringSeq& TSRMLS_DC);
bool extractStringArray(zval*, Ice::StringSeq& TSRMLS_DC);
//
+// Create a PHP instance of Ice_ProtocolVersion.
+//
+bool createProtocolVersion(zval*, const Ice::ProtocolVersion& TSRMLS_DC);
+
+//
+// Create a PHP instance of Ice_EncodingVersion.
+//
+bool createEncodingVersion(zval*, const Ice::EncodingVersion& TSRMLS_DC);
+
+//
+// Extracts the members of an encoding version.
+//
+bool extractEncodingVersion(zval*, Ice::EncodingVersion& TSRMLS_DC);
+
+//
// Convert the given exception into its PHP equivalent.
//
zval* convertException(const Ice::Exception& TSRMLS_DC);