summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--php/demo/Ice/value/Client.php192
-rw-r--r--php/demo/Ice/value/README8
-rw-r--r--php/demo/Ice/value/Value.ice49
-rw-r--r--php/demo/Ice/value/php.ini1
-rw-r--r--php/src/ice/communicator.cpp170
-rw-r--r--php/src/ice/ice_communicator.h14
-rw-r--r--php/src/ice/ice_marshal.h9
-rw-r--r--php/src/ice/ice_util.h18
-rw-r--r--php/src/ice/marshal.cpp247
-rw-r--r--php/src/ice/profile.cpp19
-rw-r--r--php/src/ice/util.cpp106
11 files changed, 766 insertions, 67 deletions
diff --git a/php/demo/Ice/value/Client.php b/php/demo/Ice/value/Client.php
new file mode 100644
index 00000000000..01fff908a79
--- /dev/null
+++ b/php/demo/Ice/value/Client.php
@@ -0,0 +1,192 @@
+<?php
+Ice_loadProfile();
+
+class PrinterI extends Printer
+{
+ function printBackwards()
+ {
+ echo strrev($this->message),"\n";
+ }
+}
+
+class DerivedPrinterI extends DerivedPrinter
+{
+ function printBackwards()
+ {
+ echo strrev($this->message),"\n";
+ }
+
+ function printUpperCase()
+ {
+ echo strtoupper($this->derivedMessage),"\n";
+ }
+}
+
+class ObjectFactory extends Ice_LocalObjectImpl implements Ice_ObjectFactory
+{
+ function create($type)
+ {
+ if($type == "::Printer")
+ {
+ return new PrinterI;
+ }
+
+ if($type == "::DerivedPrinter")
+ {
+ return new DerivedPrinterI;
+ }
+
+ assert(false);
+ return null;
+ }
+
+ function destroy()
+ {
+ }
+}
+
+try
+{
+ $base = $ICE->stringToProxy("initial:default -p 10000");
+ $initial = $base->ice_checkedCast("::Initial");
+
+ echo "\n";
+ echo "Let's first transfer a simple object, for a class without\n";
+ echo "operations, and print its contents. No factory is required\n";
+ echo "for this.\n";
+ echo "[press enter]\n";
+ fgets(STDIN);
+
+ $simple = $initial->getSimple();
+ echo "==> ",$simple->message,"\n";
+
+ echo "\n";
+ echo "Ok, this worked. Now let's try to transfer an object for a class\n";
+ echo "with operations as type ::Ice::Object. Because no factory is installed,\n";
+ echo "the class will be sliced to ::Ice::Object.\n";
+ echo "[press enter]\n";
+ fgets(STDIN);
+
+ $obj = $initial->getPrinterAsObject();
+ echo "==> The type ID of the received object is \"",get_class($obj),"\"\n";
+ assert(get_class($obj) == "ice_objectimpl");
+
+ echo "\n";
+ echo "Yes, this worked. Now let's try to transfer an object for a class\n";
+ echo "with operations as type ::Printer, without installing a factory first.\n";
+ echo "This should give us a `no factory' exception.\n";
+ echo "[press enter]\n";
+ fgets(STDIN);
+
+ $gotException = false;
+ try
+ {
+ $initial->getPrinter($printer, $printerProxy);
+ }
+ catch(Ice_NoObjectFactoryException $ex)
+ {
+ print_r($ex);
+ $gotException = true;
+ }
+ assert($gotException);
+
+ echo "\n";
+ echo "Yep, that's what we expected. Now let's try again, but with\n";
+ echo "installing an appropriate factory first. If successful, we print\n";
+ echo "the object's content.\n";
+ echo "[press enter]\n";
+ fgets(STDIN);
+
+ $factory = new ObjectFactory;
+ $ICE->addObjectFactory($factory, "::Printer");
+
+ $initial->getPrinter($printer, $printerProxy);
+ echo "==> ",$printer->message,"\n";
+
+ echo "\n";;
+ echo "Cool, it worked! Let's try calling the printBackwards() method\n";
+ echo "on the object we just received locally.\n";
+ echo "[press enter]\n";
+ fgets(STDIN);
+
+ echo "==> ";
+ $printer->printBackwards();
+
+ echo "\n";
+ echo "Now we call the same method, but on the remote object. Watch the\n";
+ echo "server's output.\n";
+ echo "[press enter]\n";
+ fgets(STDIN);
+
+ $printerProxy->printBackwards();
+
+ echo "\n";
+ echo "Next, we transfer a derived object from the server as a base\n";
+ echo "object. Since we haven't yet installed a factory for the derived\n";
+ echo "class, the derived class (::DerivedPrinter) is sliced\n";
+ echo "to its base class (::Printer).\n";
+ echo "[press enter]\n";
+ fgets(STDIN);
+
+ $derivedAsBase = $initial->getDerivedPrinter();
+ echo "==> The type ID of the received object is \"",get_class($derivedAsBase),"\"\n";
+ assert($derivedAsBase instanceof Printer);
+
+ echo "\n";
+ echo "Now we install a factory for the derived class, and try again.\n";
+ echo "Because we receive the derived object as a base object, we\n";
+ echo "we need to do a dynamic_cast<> to get from the base to the derived object.\n";
+ echo "[press enter]\n";
+ fgets(STDIN);
+
+ $ICE->addObjectFactory($factory, "::DerivedPrinter");
+
+ $derivedAsBase = $initial->getDerivedPrinter();
+ assert($derivedAsBase instanceof DerivedPrinter);
+ $derived = $derivedAsBase;
+ echo "==> dynamic_cast<> to derived object succeeded\n";
+ echo "==> The type ID of the received object is \"",get_class($derived),"\"\n";
+
+ echo "\n";
+ echo "Let's print the message contained in the derived object, and\n";
+ echo "call the operation printUppercase() on the derived object\n";
+ echo "locally.\n";
+ echo "[press enter]\n";
+ fgets(STDIN);
+
+ echo "==> ",$derived->derivedMessage,"\n";
+ echo "==> ";
+ $derived->printUppercase();
+
+ echo "\n";
+ echo "Finally, we try the same again, but instead of returning the\n";
+ echo "derived object, we throw an exception containing the derived\n";
+ echo "object.\n";
+ echo "[press enter]\n";
+ fgets(STDIN);
+
+ $gotException = false;
+ try
+ {
+ $initial->throwDerivedPrinter();
+ }
+ catch(DerivedPrinterException $ex)
+ {
+ $derived = $ex->derived;
+ assert($derived != null);
+ $gotException = true;
+ }
+ assert($gotException);
+
+ echo "==> ",$derived->derivedMessage,"\n";
+ echo "==> ";
+ $derived->printUppercase();
+
+ echo "\n";
+ echo "That's it for this demo. Have fun with Ice!\n";
+}
+catch(Ice_LocalException $ex)
+{
+ print_r($ex);
+}
+?>
diff --git a/php/demo/Ice/value/README b/php/demo/Ice/value/README
new file mode 100644
index 00000000000..5113013ef8c
--- /dev/null
+++ b/php/demo/Ice/value/README
@@ -0,0 +1,8 @@
+This is a PHP version of the Ice "value" demo client. First, start the
+C++ or Java version of the value demo server on the same host. Then
+run this client with the following command:
+
+$ php -c php.ini -f Client.php
+
+Note that this client requires user input, therefore you must run this
+example using the CLI version of the PHP interpreter.
diff --git a/php/demo/Ice/value/Value.ice b/php/demo/Ice/value/Value.ice
new file mode 100644
index 00000000000..4a69d6b6a7d
--- /dev/null
+++ b/php/demo/Ice/value/Value.ice
@@ -0,0 +1,49 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#ifndef VALUE_ICE
+#define VALUE_ICE
+
+class Simple
+{
+ string message;
+};
+
+class Printer
+{
+ string message;
+ void printBackwards();
+};
+
+class DerivedPrinter extends Printer
+{
+ string derivedMessage;
+ void printUppercase();
+};
+
+exception DerivedPrinterException
+{
+ DerivedPrinter derived;
+};
+
+class Initial
+{
+ Simple getSimple();
+ Object getPrinterAsObject();
+ void getPrinter(out Printer impl, out Printer* proxy);
+ Printer getDerivedPrinter();
+ void throwDerivedPrinter() throws DerivedPrinterException;
+};
+
+#endif
diff --git a/php/demo/Ice/value/php.ini b/php/demo/Ice/value/php.ini
new file mode 100644
index 00000000000..04f27b5db6d
--- /dev/null
+++ b/php/demo/Ice/value/php.ini
@@ -0,0 +1 @@
+ice.slice=Value.ice
diff --git a/php/src/ice/communicator.cpp b/php/src/ice/communicator.cpp
index d306ee93c1b..0788425bba4 100644
--- a/php/src/ice/communicator.cpp
+++ b/php/src/ice/communicator.cpp
@@ -51,9 +51,13 @@ static void initCommunicator(ice_object* TSRMLS_DC);
//
static function_entry _methods[] =
{
- {"__construct", PHP_FN(Ice_Communicator___construct), NULL},
- {"stringToProxy", PHP_FN(Ice_Communicator_stringToProxy), NULL},
- {"proxyToString", PHP_FN(Ice_Communicator_proxyToString), NULL},
+ {"__construct", PHP_FN(Ice_Communicator___construct), NULL},
+ {"stringToProxy", PHP_FN(Ice_Communicator_stringToProxy), NULL},
+ {"proxyToString", PHP_FN(Ice_Communicator_proxyToString), NULL},
+ {"addObjectFactory", PHP_FN(Ice_Communicator_addObjectFactory), NULL},
+ {"removeObjectFactory", PHP_FN(Ice_Communicator_removeObjectFactory), NULL},
+ {"findObjectFactory", PHP_FN(Ice_Communicator_findObjectFactory), NULL},
+ {"flushBatchRequests", PHP_FN(Ice_Communicator_flushBatchRequests), NULL},
{NULL, NULL, NULL}
};
@@ -151,6 +155,11 @@ ZEND_FUNCTION(Ice_Communicator___construct)
ZEND_FUNCTION(Ice_Communicator_stringToProxy)
{
+ if(ZEND_NUM_ARGS() != 1)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
ice_object* obj = getObject(getThis() TSRMLS_CC);
if(!obj)
{
@@ -159,11 +168,6 @@ ZEND_FUNCTION(Ice_Communicator_stringToProxy)
assert(obj->ptr);
Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
- if(ZEND_NUM_ARGS() != 1)
- {
- WRONG_PARAM_COUNT;
- }
-
char *str;
int len;
@@ -191,6 +195,11 @@ ZEND_FUNCTION(Ice_Communicator_stringToProxy)
ZEND_FUNCTION(Ice_Communicator_proxyToString)
{
+ if(ZEND_NUM_ARGS() != 1)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
ice_object* obj = getObject(getThis() TSRMLS_CC);
if(!obj)
{
@@ -199,11 +208,6 @@ ZEND_FUNCTION(Ice_Communicator_proxyToString)
assert(obj->ptr);
Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
- if(ZEND_NUM_ARGS() != 1)
- {
- WRONG_PARAM_COUNT;
- }
-
zval* zprx;
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!", &zprx, proxyClassEntry) == FAILURE)
@@ -230,6 +234,146 @@ ZEND_FUNCTION(Ice_Communicator_proxyToString)
}
}
+ZEND_FUNCTION(Ice_Communicator_addObjectFactory)
+{
+ if(ZEND_NUM_ARGS() != 2)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ ice_object* obj = getObject(getThis() TSRMLS_CC);
+ if(!obj)
+ {
+ return;
+ }
+ assert(obj->ptr);
+ Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
+
+ zval* zfactory;
+ char* id;
+ int len;
+
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "os", &zfactory, &id, &len) == FAILURE)
+ {
+ return;
+ }
+
+ //
+ // Verify that the object implements Ice_ObjectFactory.
+ //
+ // TODO: When zend_check_class is changed to also check interfaces, we can remove this code and
+ // pass the class entry for Ice_ObjectFactory to zend_parse_parameters instead.
+ //
+ zend_class_entry* ce = Z_OBJCE_P(zfactory);
+ zend_class_entry* base = findClass("Ice_ObjectFactory" TSRMLS_CC);
+ assert(base);
+ if(!checkClass(ce, base))
+ {
+ zend_error(E_ERROR, "%s(): object does not implement Ice_ObjectFactory", get_active_function_name(TSRMLS_C));
+ return;
+ }
+
+ //
+ // Retrieve the PHPObjectFactory.
+ //
+ Ice::ObjectFactoryPtr factory = (*_this)->findObjectFactory("");
+ PHPObjectFactoryPtr phpFactory = PHPObjectFactoryPtr::dynamicCast(factory);
+ assert(phpFactory);
+
+ phpFactory->addObjectFactory(zfactory, id TSRMLS_CC);
+}
+
+ZEND_FUNCTION(Ice_Communicator_removeObjectFactory)
+{
+ if(ZEND_NUM_ARGS() != 1)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ ice_object* obj = getObject(getThis() TSRMLS_CC);
+ if(!obj)
+ {
+ RETURN_NULL();
+ }
+ assert(obj->ptr);
+ Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
+
+ char* id;
+ int len;
+
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &id, len) == FAILURE)
+ {
+ RETURN_NULL();
+ }
+
+ //
+ // Retrieve the PHPObjectFactory.
+ //
+ Ice::ObjectFactoryPtr factory = (*_this)->findObjectFactory("");
+ PHPObjectFactoryPtr phpFactory = PHPObjectFactoryPtr::dynamicCast(factory);
+ assert(phpFactory);
+
+ phpFactory->removeObjectFactory(id TSRMLS_CC);
+}
+
+ZEND_FUNCTION(Ice_Communicator_findObjectFactory)
+{
+ if(ZEND_NUM_ARGS() != 1)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ ice_object* obj = getObject(getThis() TSRMLS_CC);
+ if(!obj)
+ {
+ RETURN_NULL();
+ }
+ assert(obj->ptr);
+ Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
+
+ char* id;
+ int len;
+
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &id, len) == FAILURE)
+ {
+ RETURN_NULL();
+ }
+
+ //
+ // Retrieve the PHPObjectFactory.
+ //
+ Ice::ObjectFactoryPtr factory = (*_this)->findObjectFactory("");
+ PHPObjectFactoryPtr phpFactory = PHPObjectFactoryPtr::dynamicCast(factory);
+ assert(phpFactory);
+
+ phpFactory->findObjectFactory(id, return_value TSRMLS_CC);
+}
+
+ZEND_FUNCTION(Ice_Communicator_flushBatchRequests)
+{
+ if(ZEND_NUM_ARGS() != 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ ice_object* obj = getObject(getThis() TSRMLS_CC);
+ if(!obj)
+ {
+ return;
+ }
+ assert(obj->ptr);
+ Ice::CommunicatorPtr* _this = static_cast<Ice::CommunicatorPtr*>(obj->ptr);
+
+ try
+ {
+ (*_this)->flushBatchRequests();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ }
+}
+
#ifdef WIN32
extern "C"
#endif
diff --git a/php/src/ice/ice_communicator.h b/php/src/ice/ice_communicator.h
index b5d43f3f44a..131d2839ece 100644
--- a/php/src/ice/ice_communicator.h
+++ b/php/src/ice/ice_communicator.h
@@ -25,12 +25,20 @@ extern "C"
ZEND_FUNCTION(Ice_Communicator___construct);
ZEND_FUNCTION(Ice_Communicator_stringToProxy);
ZEND_FUNCTION(Ice_Communicator_proxyToString);
+ZEND_FUNCTION(Ice_Communicator_addObjectFactory);
+ZEND_FUNCTION(Ice_Communicator_removeObjectFactory);
+ZEND_FUNCTION(Ice_Communicator_findObjectFactory);
+ZEND_FUNCTION(Ice_Communicator_flushBatchRequests);
}
#define ICE_PHP_COMMUNICATOR_FUNCTIONS \
- ZEND_FE(Ice_Communicator___construct, NULL) \
- ZEND_FE(Ice_Communicator_stringToProxy, NULL) \
- ZEND_FE(Ice_Communicator_proxyToString, NULL)
+ ZEND_FE(Ice_Communicator___construct, NULL) \
+ ZEND_FE(Ice_Communicator_stringToProxy, NULL) \
+ ZEND_FE(Ice_Communicator_proxyToString, NULL) \
+ ZEND_FE(Ice_Communicator_addObjectFactory, NULL) \
+ ZEND_FE(Ice_Communicator_removeObjectFactory, NULL) \
+ ZEND_FE(Ice_Communicator_findObjectFactory, NULL) \
+ ZEND_FE(Ice_Communicator_flushBatchRequests, NULL)
namespace IcePHP
{
diff --git a/php/src/ice/ice_marshal.h b/php/src/ice/ice_marshal.h
index 19239343658..d8ad51c02df 100644
--- a/php/src/ice/ice_marshal.h
+++ b/php/src/ice/ice_marshal.h
@@ -84,7 +84,8 @@ class AbortMarshaling
//
// PHPObjectFactory is an implementation of Ice::ObjectFactory that creates PHP objects.
-// A single instance can be used for all types.
+// It is also the registry for user-defined PHP factory implementations. A single instance
+// can be used for all types.
//
class PHPObjectFactory : public Ice::ObjectFactory
{
@@ -94,11 +95,17 @@ public:
virtual Ice::ObjectPtr create(const std::string&);
virtual void destroy();
+ void addObjectFactory(zval*, const std::string& TSRMLS_DC);
+ void removeObjectFactory(const std::string& TSRMLS_DC);
+ void findObjectFactory(const std::string&, zval* TSRMLS_DC);
+
private:
#ifdef ZTS
TSRMLS_D;
#endif
+ std::map<std::string, zval*> _factories;
};
+typedef IceUtil::Handle<PHPObjectFactory> PHPObjectFactoryPtr;
} // End of namespace IcePHP
diff --git a/php/src/ice/ice_util.h b/php/src/ice/ice_util.h
index df642753610..28173d97185 100644
--- a/php/src/ice/ice_util.h
+++ b/php/src/ice/ice_util.h
@@ -111,6 +111,11 @@ bool isNativeKey(const Slice::TypePtr&);
bool getContext(zval*, Ice::Context& TSRMLS_DC);
//
+// Determines whether a class (or interface) inherits from a base class (or interface).
+//
+bool checkClass(zend_class_entry*, zend_class_entry*);
+
+//
// Exception-safe efree.
//
class AutoEfree
@@ -123,6 +128,19 @@ private:
void* _p;
};
+//
+// Exception-safe zval destroy.
+//
+class AutoDestroy
+{
+public:
+ AutoDestroy(zval* zv) : _zv(zv) {}
+ ~AutoDestroy() { if(_zv) zval_ptr_dtor(&_zv); }
+
+private:
+ zval* _zv;
+};
+
} // End of namespace IcePHP
#endif
diff --git a/php/src/ice/marshal.cpp b/php/src/ice/marshal.cpp
index 1d44b128495..6524294b4ce 100644
--- a/php/src/ice/marshal.cpp
+++ b/php/src/ice/marshal.cpp
@@ -250,7 +250,7 @@ private:
class ObjectReader : public Ice::Object
{
public:
- ObjectReader(zend_class_entry*, const Slice::ClassDefPtr& TSRMLS_DC);
+ ObjectReader(zval*, const Slice::ClassDefPtr& TSRMLS_DC);
~ObjectReader();
virtual void __write(::IceInternal::BasicStream*) const;
@@ -259,12 +259,12 @@ public:
void setValue(zend_class_entry*, zval*);
private:
- zend_class_entry* _class;
+ zval* _value;
Slice::ClassDefPtr _type; // nil if type is ::Ice::Object
#ifdef ZTS
TSRMLS_D;
#endif
- zval* _value;
+ zend_class_entry* _class;
};
typedef IceUtil::Handle<ObjectReader> ObjectReaderPtr;
@@ -1521,28 +1521,21 @@ IcePHP::ObjectWriter::__read(IceInternal::BasicStream* is, bool rid)
//
// ObjectReader implementation.
//
-IcePHP::ObjectReader::ObjectReader(zend_class_entry* cls, const Slice::ClassDefPtr& type TSRMLS_DC) :
- _class(cls), _type(type)
+IcePHP::ObjectReader::ObjectReader(zval* val, const Slice::ClassDefPtr& type TSRMLS_DC) :
+ _value(val), _type(type)
{
#ifdef ZTS
this->TSRMLS_C = TSRMLS_C;
#endif
- //
- // Create a zval to hold the new object.
- //
- MAKE_STD_ZVAL(_value);
+ ZVAL_ADDREF(_value);
- //
- // Instantiate the new object.
- //
- object_init_ex(_value, _class);
+ _class = Z_OBJCE_P(_value);
}
IcePHP::ObjectReader::~ObjectReader()
{
- Z_OBJ_HT_P(_value)->del_ref(_value TSRMLS_CC);
- efree(_value);
+ zval_ptr_dtor(&_value);
}
void
@@ -1638,23 +1631,11 @@ IcePHP::ObjectReader::setValue(zend_class_entry* ce, zval* zv)
//
// Compare the class entries. The argument "ce" represents the formal type.
//
- if(_class != ce)
+ if(!checkClass(_class, ce))
{
- //
- // Check for inheritance.
- //
- zend_class_entry* c = _class->parent;
- while(c && c != ce)
- {
- c = c->parent;
- }
-
- if(c == NULL)
- {
- zend_error(E_ERROR, "%s(): expected object value of type %s but received %s",
- get_active_function_name(TSRMLS_C), ce->name, _class->name);
- return;
- }
+ Ice::NoObjectFactoryException ex(__FILE__, __LINE__);
+ ex.type = ce->name;
+ throw ex;
}
//
@@ -1833,6 +1814,96 @@ IcePHP::PHPObjectFactory::create(const string& scoped)
{
Ice::ObjectPtr result;
+ Profile* profile = static_cast<Profile*>(ICE_G(profile));
+ assert(profile);
+
+ //
+ // First check our map for a factory registered for this type.
+ //
+ map<string, zval*>::iterator p;
+ p = _factories.find(scoped);
+ if(p == _factories.end())
+ {
+ //
+ // Next, check for a default factory.
+ //
+ p = _factories.find("");
+ }
+
+ //
+ // If we found a factory, invoke create() on the object.
+ //
+ if(p != _factories.end())
+ {
+ zval** args[1];
+ zval* id;
+ MAKE_STD_ZVAL(id);
+ ZVAL_STRINGL(id, const_cast<char*>(scoped.c_str()), scoped.length(), 1);
+
+ zval* create;
+ MAKE_STD_ZVAL(create);
+ ZVAL_STRINGL(create, "create", sizeof("create") - 1, 1);
+
+ args[0] = &id;
+ zval* zresult = NULL;
+ int status = call_user_function_ex(NULL, &p->second, create, &zresult, 1, args, 0, NULL TSRMLS_CC);
+
+ zval_ptr_dtor(&create);
+ zval_ptr_dtor(&id);
+
+ AutoDestroy destroyResult(zresult);
+
+ //
+ // Bail out if an exception has been thrown.
+ //
+ if(EG(exception))
+ {
+ throw AbortMarshaling();
+ }
+
+ if(zresult)
+ {
+ //
+ // If the factory returned a non-null value, verify that it is an object, and that it
+ // inherits from Ice_ObjectImpl.
+ //
+ if(!ZVAL_IS_NULL(zresult))
+ {
+ if(Z_TYPE_P(zresult) != IS_OBJECT)
+ {
+ zend_error(E_ERROR, "object factory did not return an object");
+ throw AbortMarshaling();
+ }
+
+ zend_class_entry* ce = Z_OBJCE_P(zresult);
+ zend_class_entry* base = findClass("Ice_ObjectImpl" TSRMLS_CC);
+ if(!checkClass(ce, base))
+ {
+ zend_error(E_ERROR, "object returned by factory does not implement Ice_ObjectImpl");
+ throw AbortMarshaling();
+ }
+
+ //
+ // Attempt to find a class definition for the object.
+ //
+ Profile::ClassMap::iterator p;
+ while(ce != NULL && (p = profile->classes.find(ce->name)) == profile->classes.end())
+ {
+ ce = ce->parent;
+ }
+
+ Slice::ClassDefPtr def;
+ if(ce != NULL)
+ {
+ assert(p != profile->classes.end());
+ def = p->second;
+ }
+
+ return new ObjectReader(zresult, def TSRMLS_CC);
+ }
+ }
+ }
+
//
// Attempt to find a class entry for the given type id. If no class entry is
// found, or the class is abstract, then we return nil and the stream will skip
@@ -1850,14 +1921,16 @@ IcePHP::PHPObjectFactory::create(const string& scoped)
}
if(cls && (cls->ce_flags & ZEND_CE_ABSTRACT) == 0)
{
- Profile* profile = static_cast<Profile*>(ICE_G(profile));
- assert(profile);
Profile::ClassMap::iterator p = profile->classes.find(cls->name);
if(p != profile->classes.end())
{
def = p->second;
}
- result = new ObjectReader(cls, def TSRMLS_CC);
+ zval* obj;
+ MAKE_STD_ZVAL(obj);
+ object_init_ex(obj, cls);
+ result = new ObjectReader(obj, def TSRMLS_CC);
+ zval_ptr_dtor(&obj);
}
return result;
@@ -1866,6 +1939,112 @@ IcePHP::PHPObjectFactory::create(const string& scoped)
void
IcePHP::PHPObjectFactory::destroy()
{
+ //
+ // Invoke destroy() on each registered factory.
+ //
+ for(map<string, zval*>::iterator p = _factories.begin(); p != _factories.end(); ++p)
+ {
+ zval* funcName;
+ MAKE_STD_ZVAL(funcName);
+ ZVAL_STRINGL(funcName, "destroy", sizeof("destroy") - 1, 1);
+
+ zval* result = NULL;
+ int status = call_user_function_ex(NULL, &p->second, funcName, &result, 0, NULL, 0, NULL TSRMLS_CC);
+
+ zval_ptr_dtor(&funcName);
+ if(result)
+ {
+ zval_ptr_dtor(&result);
+ }
+
+ Z_OBJ_HT_P(p->second)->del_ref(p->second TSRMLS_CC);
+ zval_ptr_dtor(&p->second);
+ }
+
+ _factories.clear();
+}
+
+void
+IcePHP::PHPObjectFactory::addObjectFactory(zval* factory, const string& id TSRMLS_DC)
+{
+ map<string, zval*>::iterator p = _factories.find(id);
+ if(p != _factories.end())
+ {
+ Ice::AlreadyRegisteredException ex(__FILE__, __LINE__);
+ ex.kindOfObject = "object factory";
+ ex.id = id;
+ throwException(ex TSRMLS_CC);
+ return;
+ }
+
+ //
+ // Create a new zval with the same object handle as the factory.
+ //
+ zval* zv;
+ MAKE_STD_ZVAL(zv);
+ Z_TYPE_P(zv) = IS_OBJECT;
+ zv->value.obj = factory->value.obj;
+
+ //
+ // Increment the factory's reference count.
+ //
+ Z_OBJ_HT_P(factory)->add_ref(factory TSRMLS_CC);
+
+ //
+ // Update the factory map.
+ //
+ _factories[id] = zv;
+}
+
+void
+IcePHP::PHPObjectFactory::removeObjectFactory(const string& id TSRMLS_DC)
+{
+ map<string, zval*>::iterator p = _factories.find(id);
+ if(p == _factories.end())
+ {
+ Ice::NotRegisteredException ex(__FILE__, __LINE__);
+ ex.kindOfObject = "object factory";
+ ex.id = id;
+ throwException(ex TSRMLS_CC);
+ return;
+ }
+
+ //
+ // Decrement the factory's reference count.
+ //
+ Z_OBJ_HT_P(p->second)->del_ref(p->second TSRMLS_CC);
+
+ //
+ // Destroy the zval.
+ //
+ zval_ptr_dtor(&p->second);
+
+ //
+ // Update the factory map.
+ //
+ _factories.erase(p);
+}
+
+void
+IcePHP::PHPObjectFactory::findObjectFactory(const string& id, zval* factory TSRMLS_DC)
+{
+ map<string, zval*>::iterator p = _factories.find(id);
+ if(p == _factories.end())
+ {
+ ZVAL_NULL(factory);
+ return;
+ }
+
+ //
+ // Set the zval with the same object handle as the factory.
+ //
+ Z_TYPE_P(factory) = IS_OBJECT;
+ factory->value.obj = p->second->value.obj;
+
+ //
+ // Increment the factory's reference count.
+ //
+ Z_OBJ_HT_P(p->second)->add_ref(p->second TSRMLS_CC);
}
//
diff --git a/php/src/ice/profile.cpp b/php/src/ice/profile.cpp
index e556cb3d269..695125f850e 100644
--- a/php/src/ice/profile.cpp
+++ b/php/src/ice/profile.cpp
@@ -119,6 +119,19 @@ static const char* _coreTypes =
"{\n"
"}\n"
"\n"
+ "class Ice_ProtocolException extends Ice_LocalException\n"
+ "{\n"
+ "}\n"
+ "\n"
+ "class Ice_MarshalException extends Ice_ProtocolException\n"
+ "{\n"
+ "}\n"
+ "\n"
+ "class Ice_NoObjectFactoryException extends Ice_MarshalException\n"
+ "{\n"
+ " var $type;\n"
+ "}\n"
+ "\n"
"abstract class Ice_UserException\n"
"{\n"
"}\n"
@@ -139,6 +152,12 @@ static const char* _coreTypes =
"{\n"
" var $ice_facets = array();\n"
"}\n"
+ "\n"
+ "interface Ice_ObjectFactory implements Ice_LocalObject\n"
+ "{\n"
+ " function create($id);\n"
+ " function destroy();\n"
+ "}\n"
;
//
diff --git a/php/src/ice/util.cpp b/php/src/ice/util.cpp
index b24ac10626f..83002e49fde 100644
--- a/php/src/ice/util.cpp
+++ b/php/src/ice/util.cpp
@@ -376,15 +376,13 @@ IcePHP::throwException(const IceUtil::Exception& ex TSRMLS_DC)
//
EG(exception) = zex;
}
- catch(const Ice::LocalException& e)
+ catch(const Ice::NoObjectFactoryException& e)
{
- //
- // All other local exceptions are raised as UnknownLocalException.
- //
- zend_class_entry* cls = findClass("Ice_UnknownLocalException" TSRMLS_CC);
+ string name = e.ice_name();
+ zend_class_entry* cls = findClassScoped(name TSRMLS_CC);
if(!cls)
{
- zend_error(E_ERROR, "unable to find class Ice_UnknownLocalException");
+ zend_error(E_ERROR, "unable to find class %s", name.c_str());
return;
}
@@ -397,20 +395,72 @@ IcePHP::throwException(const IceUtil::Exception& ex TSRMLS_DC)
}
//
- // Set the unknown member.
+ // Set the type member.
//
- zval* unknown;
- MAKE_STD_ZVAL(unknown);
- ostringstream ostr;
- e.ice_print(ostr);
- string str = ostr.str();
- ZVAL_STRINGL(unknown, const_cast<char*>(str.c_str()), str.length(), 1);
- if(add_property_zval(zex, "unknown", unknown) == FAILURE)
+ zval* type;
+ MAKE_STD_ZVAL(type);
+ ZVAL_STRINGL(type, const_cast<char*>(e.type.c_str()), e.type.length(), 1);
+ if(add_property_zval(zex, "type", type) == FAILURE)
{
- zend_error(E_ERROR, "unable to set unknown member of %s", cls->name);
+ zend_error(E_ERROR, "unable to set type member of %s", cls->name);
return;
}
- zval_ptr_dtor(&unknown); // add_property_zval increments the refcount
+ zval_ptr_dtor(&type); // add_property_zval increments the refcount
+
+ //
+ // Throw the exception.
+ //
+ EG(exception) = zex;
+ }
+ catch(const Ice::LocalException& e)
+ {
+ zval* zex;
+ MAKE_STD_ZVAL(zex);
+
+ //
+ // See if we have a PHP class for the exception, otherwise raise UnknownLocalException.
+ //
+ string name = e.ice_name();
+ zend_class_entry* cls = findClassScoped(name TSRMLS_CC);
+ if(cls)
+ {
+ if(object_init_ex(zex, cls) != SUCCESS)
+ {
+ zend_error(E_ERROR, "unable to create exception %s", cls->name);
+ return;
+ }
+ }
+ else
+ {
+ cls = findClass("Ice_UnknownLocalException" TSRMLS_CC);
+ if(!cls)
+ {
+ zend_error(E_ERROR, "unable to find class Ice_UnknownLocalException");
+ return;
+ }
+
+ if(object_init_ex(zex, cls) != SUCCESS)
+ {
+ zend_error(E_ERROR, "unable to create exception %s", cls->name);
+ return;
+ }
+
+ //
+ // Set the unknown member.
+ //
+ zval* unknown;
+ MAKE_STD_ZVAL(unknown);
+ ostringstream ostr;
+ e.ice_print(ostr);
+ string str = ostr.str();
+ ZVAL_STRINGL(unknown, const_cast<char*>(str.c_str()), str.length(), 1);
+ if(add_property_zval(zex, "unknown", unknown) == FAILURE)
+ {
+ zend_error(E_ERROR, "unable to set unknown member of %s", cls->name);
+ return;
+ }
+ zval_ptr_dtor(&unknown); // add_property_zval increments the refcount
+ }
//
// Throw the exception.
@@ -658,3 +708,27 @@ IcePHP::getContext(zval* zv, Ice::Context& ctx TSRMLS_DC)
return true;
}
+
+bool
+IcePHP::checkClass(zend_class_entry* ce, zend_class_entry* base)
+{
+ while(ce != NULL)
+ {
+ if(ce == base)
+ {
+ return true;
+ }
+
+ for(zend_uint i = 0; i < ce->num_interfaces; ++i)
+ {
+ if(checkClass(ce->interfaces[i], base))
+ {
+ return true;
+ }
+ }
+
+ ce = ce->parent;
+ }
+
+ return false;
+}