Slice identifiers map to PHP identifiers of the same name, unless the Slice identifier conflicts with a PHP reserved word, in which case the mapped identifier is prefixed with an underscore. For example, the Slice identifier
echo is mapped as
_echo.
A flattened mapping is used for identifiers defined within Slice modules because PHP does not have an equivalent to C++ namespaces or Java packages. The flattened mapping uses underscores to separate the components of a fully-scoped name. For example, consider the following Slice definition:
module M {
enum E { one, two, three };
};
In this case, the Slice identifier M::E is flattened to the PHP identifier
M_E.
Note that when checking for a conflict with a PHP reserved word, only the fully-scoped, flattened identifier is considered. For example, the Slice identifier
M::function is mapped as
M_function, despite the fact that
function is a PHP reserved word. There is no need to map it as
M__function (with two underscores) because
M_function does not conflict with a PHP reserved word.
However, it is still possible for the flattened mapping to generate identifiers that conflict with PHP reserved words. For instance, the Slice identifier
require::once must be mapped as
_require_once in order to avoid conflict with the PHP reserved word
require_once.
PHP has a limited set of primitive types: boolean,
integer,
double, and
string. The Slice built-in types are mapped to PHP types as shown in
Table 28.2.
PHP’s integer type may not accommodate the range of values supported by Slice’s
long type, therefore
long values that are outside this range are mapped as strings. Scripts must be prepared to receive an integer or string from any operation that returns a
long value.
enum Fruit { Apple, Pear, Orange };
class Fruit {
const Apple = 0;
const Pear = 1;
const Orange = 2;
}
A Slice structure maps to a PHP class containing a public variable for each member of the structure. The class also provides a constructor whose arguments correspond to the data members. This allows you to instantiate and initialize the class in a single statement (instead of having to first instantiate the class and then assign to its members). Each argument provides a default value appropriate for the member’s type.
struct Employee {
long number;
string firstName;
string lastName;
};
class Employee {
function __construct($number=0, $firstName='', $lastName='')
{
// ...
}
public $number;
public $firstName;
public $lastName;
}
Slice sequences are mapped to native PHP indexed arrays. The first element of the Slice sequence is contained at index 0 (zero) of the PHP array, followed by the remaining elements in ascending index order.
// Make a small platter with one Apple and one Orange
//
$platter = array(Fruit::Apple, Fruit::Orange);
The Ice run time validates the elements of an array to ensure that they are compatible with the declared type and reports an error if an incompatible type is encountered.
Slice dictionaries map to native PHP associative arrays. The PHP mapping does not currently support all Slice dictionary types, however, because native PHP associative arrays support only integer and string key types. A Slice dictionary whose key type is
boolean,
byte,
short,
int or
long is mapped as an associative array with an integer key.
1 A Slice dictionary with a string key type is mapped as associative array with a string key. All other key types cause a warning to be generated.
$e1 = new Employee;
$e1‑>number = 42;
$e1‑>firstName = "Stan";
$e1‑>lastName = "Lipmann";
$e2 = new Employee;
$e2‑>number = 77;
$e2‑>firstName = "Herb";
$e2‑>lastName = "Sutter";
$em = array($e1‑>number => $e1, $e2‑>number => $e2);
const bool AppendByDefault = true;
const byte LowerNibble = 0x0f;
const string Advice = "Don't Panic!";
const short TheAnswer = 42;
const double PI = 3.1416;
enum Fruit { Apple, Pear, Orange };
const Fruit FavoriteFruit = Pear;
define("AppendByDefault", true);
define("LowerNibble", 15);
define("Advice", "Don't Panic!");
define("TheAnswer", 42);
define("PI", 3.1416);
class Fruit {
const Apple = 0;
const Pear = 1;
const Orange = 2;
}
define("FavoriteFruit", Fruit::Pear);
A Slice exception maps to a PHP class. For each exception member, the corresponding class contains a public variable of the same name. The class also provides a constructor whose arguments correspond to the data members. This allows you to instantiate and initialize the class in a single statement (instead of having to first instantiate the class and then assign to its members). Each argument provides a default value appropriate for the member’s type. For derived exceptions, the constructor accepts one argument for each base exception member, plus one argument for each derived exception member, in base-to-derived order.
All user exceptions ultimately derive from Ice_UserException (which, in turn, derives from
Ice_Exception, which derives from PHP’s base
Exception class):
abstract class Ice_Exception extends Exception {
function __construct($_message = '') {
...
}
}
abstract class Ice_UserException extends Ice_Exception {
function __construct($_message = '') {
...
}
}
If the exception derives from a base exception, the corresponding PHP class derives from the mapped class for the base exception. Otherwise, if no base exception is specified, the corresponding class derives from
Ice_UserException.
exception GenericError {
string reason;
};
exception BadTimeVal extends GenericError {};
exception BadZoneName extends GenericError {};
class GenericError extends Ice_UserException {
function __construct($_message='', $reason='') {
...
}
public $reason;
}
class BadTimeVal extends GenericError {
function __construct($_message='', $reason='') {
...
}
}
class BadZoneName extends GenericError {
function __construct($_message='', $reason='') {
...
}
}
try {
...
} catch(BadZoneName $ex) {
// Handle BadZoneName
} catch(GenericError $ex) {
// Handle GenericError
} catch(Ice_Exception $ex) {
// Handle all other Ice exceptions
print_r($ex);
}
The Ice run time throws run-time exceptions for a number of pre-defined error conditions. All run-time exceptions directly or indirectly derive from
Ice_LocalException (which, in turn, derives from
Ice_Exception, which derives from PHP’s base
Exception class):
abstract class Ice_Exception extends Exception {
function __construct($_message = '') {
...
}
}
abstract class Ice_LocalException extends Ice_Exception {
function __construct($_message = '') {
...
}
}
An inheritance diagram for user and run-time exceptions appears in Figure 4.4 on
page 122. Note however that the PHP mapping only defines classes for the local exceptions listed below:
Instances of all remaining local exceptions are converted to the class Ice_UnknownLocalException. The
unknown member of this class contains a string representation of the original exception.
A Slice interface maps to a PHP interface. Each operation in the interface maps to a method of the same name, as described in
Section 28.4.9. The inheritance structure of the Slice interface is preserved in the PHP mapping, and all interfaces ultimately derive from
Ice_Object:
interface A {
void opA();
};
interface B extends A {
void opB();
};
interface A implements Ice_Object
{
function opA();
}
interface B implements A
{
function opB();
}
A Slice class maps to an abstract PHP class. Each operation in the class maps to an abstract method of the same name, as described in
Section 28.4.9. For each Slice data member, the PHP class contains a public variable of the same name. The class also provides a constructor whose arguments correspond to the data members. This allows you to instantiate and initialize the class in a single statement (instead of having to first instantiate the class and then assign to its members). Each argument provides a default value appropriate for the member’s type. For derived classes, the constructor accepts one argument for each base class member, plus one argument for each derived class member, in base-to-derived order.
The inheritance structure of the Slice class is preserved in the PHP mapping, and all classes ultimately derive from
Ice_ObjectImpl (which, in turn, implements
Ice_Object):
class Ice_ObjectImpl implements Ice_Object
{
}
class TimeOfDay {
short hour; // 0 ‑ 23
short minute; // 0 ‑ 59
short second; // 0 ‑ 59
string format(); // Return time as hh:mm:ss
};
abstract class TimeOfDay extends Ice_ObjectImpl
{
function __construct($hour=0, $minute=0, $second=0) {
...
}
public $hour;
public $minute;
public $second;
abstract function format();
}
By default, data members of classes are mapped exactly as for structures and exceptions: for each data member in the Slice definition, the generated class contains a corresponding public variable.
If you wish to restrict access to a data member, you can modify its visibility using the
protected metadata directive. The presence of this directive causes the Slice compiler to generate the data member with protected visibility. As a result, the member can be accessed only by the class itself or by one of its subclasses. For example, the
TimeOfDay class shown below has the
protected metadata directive applied to each of its data members:
class TimeOfDay {
["protected"] short hour; // 0 ‑ 23
["protected"] short minute; // 0 ‑ 59
["protected"] short second; // 0 ‑ 59
string format(); // Return time as hh:mm:ss
};
abstract class TimeOfDay extends Ice_ObjectImpl
{
function __construct($hour=0, $minute=0, $second=0) {
...
}
protected $hour;
protected $minute;
protected $second;
abstract function format();
}
For a class in which all of the data members are protected, the metadata directive can be applied to the class itself rather than to each member individually. For example, we can rewrite the
TimeOfDay class as follows:
["protected"] class TimeOfDay {
short hour; // 0 ‑ 23
short minute; // 0 ‑ 59
short second; // 0 ‑ 59
string format(); // Return time as hh:mm:ss
};
Class factories are installed by invoking addObjectFactory on the communicator (see
Section 28.4.11). A factory must implement the interface
Ice_ObjectFactory, defined as follows:
interface Ice_ObjectFactory implements Ice_LocalObject
{
function create(/* string */ $id);
function destroy();
}
class TimeOfDayI extends TimeOfDay {
function format()
{
return sprintf("%02d:%02d:%02d", $this‑>hour,
$this‑>minute, $this‑>second);
}
}
class TimeOfDayFactory extends Ice_LocalObjectImpl
implements Ice_ObjectFactory {
function create($id)
{
return new TimeOfDayI;
}
function destroy() {}
}
$ICE‑>addObjectFactory(new TimeOfDayFactory, "::M::TimeOfDay");
Each operation defined in a Slice class or interface is mapped to a PHP function of the same name. Furthermore, each parameter of an operation is mapped to a PHP parameter of the same name. Since PHP is a loosely-typed language, no parameter types are specified.
2
struct NumberAndString {
int x;
string str;
};
sequence<string> StringSeq;
dictionary<long, StringSeq> StringTable;
interface ClientToServer {
void op1(int i, float f, bool b, string s);
void op2(NumberAndString ns, StringSeq ss, StringTable st);
void op3(ClientToServer* proxy);
};
Given a proxy to a ClientToServer interface, the client code can pass parameters as shown below:
$p = ... // Get proxy...
$p‑>op1(42, 3.14, true, "Hello world!"); // Pass simple literals
$i = 42;
$f = 3.14;
$b = true;
$s = "Hello world!";
$p‑>op1($i, $f, $b, $s); // Pass simple variables
$ns = new NumberAndString();
$ns‑>x = 42;
$ns‑>str = "The Answer";
$ss = array("Hello world!");
$st = array(0 => $ss);
$p‑>op2($ns, $ss, $st); // Pass complex variables
$p‑>op3($p); // Pass proxy
struct NumberAndString {
int x;
string str;
};
sequence<string> StringSeq;
dictionary<long, StringSeq> StringTable;
interface ServerToClient {
int op1(out float f, out bool b, out string s);
void op2(out NumberAndString ns,
out StringSeq ss,
out StringTable st);
void op3(out ServerToClient* proxy);
};
Given a proxy to a ServerToClient interface, the client code can receive the results as shown below:
$p = ... // Get proxy...
$i = $p‑>op1(&$f, &$b, &$s);
$p‑>op2(&$ns, &$ss, &$st);
$p‑>op3(&$proxy);
Some Slice types naturally have "empty" or "not there" semantics. Specifically, sequences, dictionaries, and strings all can be
null, but the corresponding Slice types do not have the concept of a null value. To make life with these types easier, whenever you pass
null as a parameter or data member of type sequence, dictionary, or string, the Ice run time automatically sends an empty sequence, dictionary, or string to the receiver.
This behavior is useful as a convenience feature: especially for deeply-nested data types, members that are sequences, dictionaries, or strings automatically arrive as an empty value at the receiving end. This saves you having to explicitly initialize, for example, every string element in a large sequence before sending the sequence in order to avoid a run-time error. Note that using null parameters in this way does
not create null semantics for Slice sequences, dictionaries, or strings. As far as the object model is concerned, these do not exist (only
empty sequences, dictionaries, and strings do). For example, it makes no difference to the receiver whether you send a string as
null or as an empty string: either way, the receiver sees an empty string.
An untyped proxy is equivalent to the Slice type
Object*. The communicator operation
stringToProxy returns an untyped proxy, as do some of the core proxy methods. A script cannot invoke user-defined operations on an untyped proxy, nor can an untyped proxy be passed as an argument where a typed proxy is expected.
A typed proxy is one that has been associated with a Slice class or interface type. There are two ways a script can obtain a typed proxy:
2.
By using the methods ice_checkedCast or
ice_uncheckedCast. The method signatures are shown below:
interface Ice_ObjectPrx {
/* ... standard proxy methods ... */
function ice_uncheckedCast(/* string */ $type,
/* string */ $facet = null,
/* array */ $ctx = null);
function ice_checkedCast(/* string */ $type,
/* string */ $facet = null,
/* array */ $ctx = null);
}
These methods, which are equivalent to the static methods checkedCast and
uncheckedCast in other Ice language mappings, are defined in PHP as member functions of the proxy class
Ice_ObjectPrx. The first argument is a Slice type id, such as
"::Demo::Hello", denoting the interface that you intend to access via this proxy. The optional second parameter specifies the name of a facet (see
Chapter 34), and the third parameter supplies a request context (see
Section 32.12). If you need to supply a context but not a facet, you may also supply the context as the second parameter. The Slice definition for the specified type id must already be loaded.
$obj = $ICE‑>stringToProxy("a:tcp ‑p 12345");
$obj‑>opA(); // WRONG!
$a = $obj‑>ice_checkedCast("::A");
$a‑>opA(); // OK
Attempting to invoke opA on
$obj would result in a fatal error because
$obj is an untyped proxy.
The base proxy class Ice_ObjectPrx supports a variety of methods for customizing a proxy (see
Section 32.11). Since proxies are immutable, each of these "factory methods" returns a copy of the original proxy that contains the desired modification. For example, you can obtain a proxy configured with a ten second timeout as shown below:
// PHP$proxy = $ICE->stringToProxy(...);
$proxy = $proxy->ice_timeout(10000);
Most proxy factory methods preserve the proxy’s existing type, allowing you to invoke factory methods without the need to subsequently downcast the new proxy:
// PHP$base = $ICE->stringToProxy(...);
$hello = $base->ice_checkedCast("::Demo::Hello");
$hello = $hello->ice_timeout(10000); // Type is not discarded
$hello->sayHello();
The only exceptions are the factory methods ice_facet and
ice_identity. Calls to either of these methods may produce a proxy for an object of an unrelated type, therefore they return a base proxy that you must subsequently down-cast to an appropriate type.
All remote operations on a proxy support an optional final parameter of type Ice::Context representing the request context. The standard PHP mapping for the request context is an associative array in which the keys and values are strings. For example, the code below illustrates how to invoke
ice_ping with a request context:
$p = $ICE‑>stringToProxy("a:tcp ‑p 12345");
$ctx = array("theKey" => "theValue");
$p‑>ice_ping($ctx);
Certain core proxy operations use the type Ice_Identity, which is the PHP mapping for the Slice type
Ice::Identity (see
Section 32.5). This type is mapped using the standard rules for Slice structures, therefore it is defined as follows:
class Ice_Identity {
var $name;
var $category;
}
Two communicator functions are provided for converting Ice_Identity values to and from a string representation. See
Section 28.4.11 for details.
A PHP script can configure a proxy to use a router or locator via the ice_router and
ice_locator factory methods, respectively. These methods are described in
Section 32.11.2, but there are special considerations when using PHP. Specifically, the Slice definitions for the
Ice::Router and
Ice::Locator interfaces must be loaded in order to use these methods.
28.4.11 Mapping for Ice::Communicator
Since the Ice extension for PHP provides only client-side facilities, many of the operations provided by
Ice::Communicator operations are not relevant, therefore the PHP mapping supports a subset of the communicator operations. The mapping for
Ice::Communicator is shown below:
interface Ice_Communicator {
function getProperty(/* string */ $name,
/* string */ $def = "");
function stringToProxy(/* string */ $str);
function proxyToString(/* Ice_ObjectPrx */ $prx);
function propertyToProxy(/* string */ $property);
function stringToIdentity(/* string */ $str);
function identityToString(/* Ice_Identity */ $id);
function addObjectFactory(/* Ice_ObjectFactory */ $factory,
/* string */ $id);
function findObjectFactory(/* string */ $id);
function flushBatchRequests();
}
The getProperty method returns the value of a configuration property. If the property is not defined, the method returns the default value if one was provided, otherwise the method returns an empty string.
See Section 32.11.2for a description of the remaining operations.
PHP scripts are not allowed to create or destroy communicators. Rather, a communicator is created prior to each PHP request, and is destroyed after the request completes.
The communicator instance created for a request is available to the script via the global variable
$ICE. Scripts should not attempt to assign a different value to this variable. As with any global variable, scripts that need to use
$ICE from within a function must declare the variable as global:
function printProxy($prx) {
global $ICE;
print $ICE‑>proxyToString($prx);
}