diff options
Diffstat (limited to 'php/src')
-rw-r--r-- | php/src/IcePHP/Endpoint.cpp | 36 | ||||
-rw-r--r-- | php/src/IcePHP/Init.cpp | 18 | ||||
-rw-r--r-- | php/src/IcePHP/Operation.cpp | 156 | ||||
-rw-r--r-- | php/src/IcePHP/Proxy.cpp | 80 | ||||
-rw-r--r-- | php/src/IcePHP/Types.cpp | 470 | ||||
-rw-r--r-- | php/src/IcePHP/Types.h | 74 | ||||
-rw-r--r-- | php/src/IcePHP/Util.cpp | 375 | ||||
-rw-r--r-- | php/src/IcePHP/Util.h | 22 |
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); |