Table of Contents Previous Next
Logo
Ice Extension for PHP : 28.4 Client-Side Slice-to-PHP Mapping
Copyright © 2003-2007 ZeroC, Inc.

28.4 Client-Side Slice-to-PHP Mapping

This section describes the PHP mapping for Slice types.

28.4.1 Mapping for Identifiers

Slice identifiers map to PHP identifiers of the same name, unless the Slice identi­fier 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.

28.4.2 Mapping for Simple Built‑in Types

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.
Table 28.2. Mapping of Slice built‑in types to PHP.
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.

28.4.3 Mapping for User-Defined Types

Slice supports user-defined types: enumerations, structures, sequences, and dictio­naries.

Mapping for Enumerations

Enumerations map to a PHP class containing a constant definition for each enumerator. For example:
enum Fruit { Apple, Pear, Orange };
The PHP mapping is shown below:
class Fruit {
    const Apple = 0;
    const Pear = 1;
    const Orange = 2;
}
The enumerators can be accessed in PHP code as Fruit::Apple, etc.

Mapping for Structures

Slice structures map to PHP classes. For each Slice data member, the PHP class contains a variable of the same name. For example, here is our Employee structure from Section 4.9.4 yet again:
struct Employee {
    long number;
    string firstName;
    string lastName;
};
This structure is mapped to the following PHP class:
class Employee {
    var $number;
    var $firstName;
    var $lastName;
}

Mapping for Sequences

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.
Here is the definition of our FruitPlatter sequence from Section 4.9.3:
sequence<Fruit> FruitPlatter;
You can create an instance of this sequence as shown below:
// Make a small platter with one Apple and one Orange
//
$platter = array(Fruit::Apple, Fruit::Orange);

Mapping for Dictionaries

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.
Here is the definition of our EmployeeMap from Section 4.9.4:
dictionary<long, Employee> EmployeeMap;
You can create an instance of this dictionary as shown below:
$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);

28.4.4 Mapping for Constants

Slice constant definitions map to corresponding calls to the PHP function define. Here are the constant definitions we saw in Section 4.9.5:
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;
Here are the equivalent PHP definitions for these constants:
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);

28.4.5 Mapping for Exceptions

A Slice exception maps to a PHP class. For each exception member, the corre­sponding class contains a variable of the same name. All user exceptions ulti­mately 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 = '') {
        ...
    }
}
The optional string argument to the constructor is passed unmodified to the Exception constructor.
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 excep­tion is specified, the corresponding class derives from Ice_UserException.
Here is a fragment of the Slice definition for our world time server from Section 4.10.5:
exception GenericError {
    string reason;
};
exception BadTimeVal extends GenericError {};
exception BadZoneName extends GenericError {};
These exceptions are mapped as the following PHP classes:
class GenericError extends Ice_UserException {
    function __construct($message = '') {
        ...
    }

    var $reason;
}

class BadTimeVal extends GenericError {
    function __construct($message = '') {
        ...
    }
}

class BadZoneName extends GenericError {
    function __construct($message = '') {
        ...
    }
}
An application can catch these exceptions as shown below:
try {
    ...
} catch(BadZoneName $ex) {
    // Handle BadZoneName
} catch(GenericError $ex) {
    // Handle GenericError
} catch(Ice_Exception $ex) {
    // Handle all other Ice exceptions
    print_r($ex);
}

28.4.6 Mapping for Run-Time Exceptions

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 110. Note however that the PHP mapping only defines classes for the local exceptions listed below:
• Ice_LocalException
• Ice_UnknownException
• Ice_UnknownLocalException
• Ice_UnknownUserException
• Ice_RequestFailedException
• Ice_ObjectNotExistException
• Ice_FacetNotExistException
• Ice_OperationNotExistException
• Ice_ProtocolException
• Ice_MarshalException
• Ice_NoObjectFactoryException
• Ice_UnexpectedObjectException
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.

28.4.7 Mapping for Interfaces

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 struc­ture of the Slice interface is preserved in the PHP mapping, and all interfaces ulti­mately derive from Ice_Object:
interface Ice_Object {};
For example, consider the following Slice definitions:
interface A {
    void opA();
};
interface B extends A {
    void opB();
};
These interfaces are mapped to PHP interfaces as shown below:
interface A implements Ice_Object
{
    function opA();
}
interface B implements A
{
    function opB();
}

28.4.8 Mapping for Classes

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 variable of the same name. The inher­itance 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
{
}
Consider the following class definition:
class TimeOfDay {
    short hour;         // 0  23
    short minute;       // 0  59
    short second;       // 0  59
    string format();    // Return time as hh:mm:ss
};
The PHP mapping for this class is shown below:
abstract class TimeOfDay extends Ice_ObjectImpl
{
    var $hour;
    var $minute;
    var $second;
    abstract function format();
}

Class Factories

Class factories are installed by invoking addObjectFactory on the communi­cator (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();
}
For example, we can define and install a factory for the TimeOfDay class as shown below:
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");

28.4.9 Mapping for Operations

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, with out parameters passed by reference. Since PHP is a loosely-typed language, no parameter types are specified.2
Consider the following interface:
interface I {
    float op(string s, out int i);
};
The PHP mapping for this interface is shown below:
interface I {
    function op($s, &$i);
}

28.4.10 Mapping for Proxies

The PHP mapping for Slice proxies uses a single interface, Ice_ObjectPrx, to represent all proxy types.

Typed Versus Untyped Proxies

A proxy can be typed or untyped. All proxies, whether they are typed or untyped, support the core proxy methods described in the next section.
An untyped proxy is equivalent to the Slice type Object*. The communicator operation stringToProxy returns an untyped proxy, as do several 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:
1. By receiving it as the result of a remote invocation that returns a typed proxy.
2. By using the core proxy methods ice_checkedCast or ice_uncheckedCast.
For example, suppose our script needs to obtain a typed proxy for interface A, shown below:
interface A {
    void opA();
};
Here are the steps our script performs:
$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.

Core Proxy Methods

The Ice_ObjectPrx interface supplies the standard proxy methods described in Section 32.10.2, as well as two additional methods for downcasting purposes:
interface Ice_ObjectPrx {
    /* ... standard proxy methods ... */
    function ice_uncheckedCast(/* string */ $type,
                               /* string */ $facet = null);
    function ice_checkedCast(/* string */ $type,
                             /* string */ $facet = null);
}
To demonstrate the use of proxy factory methods, consider this example:
$p = $ICE>stringToProxy("a:tcp p 12345");
$p = $p>ice_oneway();
$p = $p>ice_secure(true);
$p = $p>ice_uncheckedCast("::A");
The script receives an untyped proxy as the return value of stringToProxy. Since the stringified proxy did not contain any proxy options, it is configured by default as a twoway, insecure proxy with no timeout. However, our goal is to obtain a secure oneway proxy for interface A, therefore we invoke ice_oneway, followed by ice_secure. At this point, we have an untyped proxy configured for secure oneway invocations. Finally, we call ice_uncheckedCast to obtain a typed proxy.3
Note that this process can be simplified by chaining the proxy factory methods, as shown below:
$p = $ICE>stringToProxy("a:tcp p 12345");
$p = $p>ice_oneway()>ice_secure(true)>ice_uncheckedCast("::A");
The order that the proxy factory methods are invoked is usually not important, except in the case of ice_checkedCast and ice_uncheckedCast. For example, if the script above had invoked ice_uncheckedCast first, followed by the other factory methods, then the result would have been an untyped proxy:
$p = $ICE>stringToProxy("a:tcp p 12345");
$p = $p>ice_uncheckedCast("::A"); // WRONG!
$p = $p>ice_oneway();
$p = $p>ice_secure(true);
The reason for this unexpected behavior is that most of the factory methods return an untyped proxy, thereby discarding any type that might have been associated with the original proxy. By invoking ice_oneway on the typed proxy returned from ice_uncheckedCast, the script has lost its typed proxy.

Request Context

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);
Alternatively, a script can specify a default request context using the proxy method ice_newContext. See Section 32.11 for more information on request contexts.

Identity

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.

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.10.2for a description of the remaining operations.

Communicator Lifecycle

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.

Accessing the Communicator

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);
}

Communicator Configuration

The profile loaded by the script determines the communicator’s configuration. See Section 28.3 for more information.

1
Boolean values are treated as integers, with false equivalent to 0 (zero) and true equivalent to 1 (one).

2
PHP5 introduces the notion of “type hints” that allow you to specify the formal type of object parameters. This would enable the Slice mapping to specify type hints for parameters of type struct, interface, class and proxy. Unfortunately, PHP5 does not currently allow a parameter defined with a type hint to receive a null value, therefore the Slice mapping does not use type hints for parameters.

3
We cannot use ice_checkedCast on a proxy configured for oneway invocations.

Table of Contents Previous Next
Logo