/trunk/Doc/Manual/Php.html
HTML | 1211 lines | 908 code | 233 blank | 70 comment | 0 complexity | b27706edc56d21a0657cd597db771ce2 MD5 | raw file
Possible License(s): LGPL-2.1, Cube, GPL-3.0, 0BSD, GPL-2.0
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <!-- Hand crafted HTML -->
- <html>
- <head>
- <title>SWIG and PHP</title>
- <link rel="stylesheet" type="text/css" href="style.css">
- </head>
- <body bgcolor="#ffffff">
- <H1><a name="Php"></a>32 SWIG and PHP</H1>
- <!-- INDEX -->
- <div class="sectiontoc">
- <ul>
- <li><a href="#Php_nn1">Generating PHP Extensions</a>
- <ul>
- <li><a href="#Php_nn1_1">Building a loadable extension</a>
- <li><a href="#Php_nn1_3">Using PHP Extensions</a>
- </ul>
- <li><a href="#Php_nn2">Basic PHP interface</a>
- <ul>
- <li><a href="#Php_nn2_1">Constants</a>
- <li><a href="#Php_nn2_2">Global Variables</a>
- <li><a href="#Php_nn2_3">Functions</a>
- <li><a href="#Php_nn2_4">Overloading</a>
- <li><a href="#Php_nn2_5">Pointers and References</a>
- <li><a href="#Php_nn2_6">Structures and C++ classes</a>
- <ul>
- <li><a href="#Php_nn2_6_1">Using <tt>-noproxy</tt></a>
- <li><a href="#Php_nn2_6_2">Constructors and Destructors</a>
- <li><a href="#Php_nn2_6_3">Static Member Variables</a>
- <li><a href="#Php_nn2_6_4">Static Member Functions</a>
- </ul>
- <li><a href="#Php_nn2_7">PHP Pragmas, Startup and Shutdown code</a>
- </ul>
- <li><a href="#Php_nn3">Cross language polymorphism</a>
- <ul>
- <li><a href="#Php_nn3_1">Enabling directors</a>
- <li><a href="#Php_nn3_2">Director classes</a>
- <li><a href="#Php_nn3_3">Ownership and object destruction</a>
- <li><a href="#Php_nn3_4">Exception unrolling</a>
- <li><a href="#Php_nn3_5">Overhead and code bloat</a>
- <li><a href="#Php_nn3_6">Typemaps</a>
- <li><a href="#Php_nn3_7">Miscellaneous</a>
- </ul>
- </ul>
- </div>
- <!-- INDEX -->
- <p>
- SWIG supports generating wrappers for PHP5. Support for PHP4 was removed
- in SWIG 1.3.37. The PHP developers are no longer making new PHP4 releases,
- and won't even be patching critical security issues after 2008-08-08, so it
- doesn't make much sense for SWIG to continue to support PHP4 now. If you
- really need to continue to use PHP4, just stick with SWIG 1.3.36.
- </p>
- <p>
- Currently any PHP5 release should work, but we don't regularly test with
- PHP < 5.3.
- </p>
- <p>
- In this chapter, we discuss SWIG's support of PHP. The PHP module
- was extensively rewritten in release 1.3.26, and support for generating
- OO wrappers for PHP5 was added in 1.3.30. The PHP module now supports most
- of the features available in some of the other languages.
- </p>
- <p>
- In order to use this module, you will need to have a copy of the PHP5
- include files to compile the SWIG generated files. If you installed
- PHP from a binary package, you may need to install a "php-dev" or "php-devel"
- package for these to be installed. You can find out where these files are
- by running <tt>php-config --includes</tt>. To use the built PHP module you
- will need either the php binary or the Apache php module. If you want to build
- your extension into php directly, you will need the complete PHP source tree
- available.
- </p>
- <H2><a name="Php_nn1"></a>32.1 Generating PHP Extensions</H2>
- <p>
- To build a PHP extension, run swig using the <tt>-php</tt> option as
- follows:
- </p>
- <div class="code"><pre>
- swig -php example.i
- </pre></div>
- <p>
- This will produce 3 files example_wrap.c, php_example.h and
- example.php. The first file, <tt>example_wrap.c</tt> contains all of
- the C code needed to build a PHP extension. The second file,
- <tt>php_example.h</tt> contains the header information needed if
- you wish to statically link the extension into the php interpreter.
- The third file,
- <tt>example.php</tt> can be included by PHP scripts. It attempts to
- dynamically load the extension and contains extra php code specified
- in the interface file. If wrapping C++ code with PHP classes, it will
- also contain PHP5 class wrappers.
- </p>
- <p>
- SWIG can generate PHP extensions from C++ libraries as well when
- given the <tt>-c++</tt> option. The support for C++ is discussed in
- more detail in <a href="#Php_nn2_6">section 27.2.6</a>.
- </p>
- <p>
- The usual (and recommended) way is to build the extension as a separate
- dynamically loaded module (which is supported by all modern operating
- systems). You can then specify that this be loaded
- automatically in <tt>php.ini</tt> or load it explicitly for any script which
- needs it.
- </p>
- <p>
- It is also possible to rebuild PHP from source so that your module is
- statically linked into the php executable/library. This is a lot more
- work, and also requires a full rebuild of PHP to update your module,
- and it doesn't play nicely with package system. We don't recommend
- this approach, or provide explicit support for it.
- </p>
- <H3><a name="Php_nn1_1"></a>32.1.1 Building a loadable extension</H3>
- <p>
- To build your module as a dynamically loadable extension, use compilation
- commands like these (if you aren't using GCC, the commands will be different,
- and there may be some variation between platforms - these commands should at
- least work for Linux though):
- </p>
- <div class="code"><pre>
- gcc `php-config --includes` -fpic -c example_wrap.c
- gcc -shared example_wrap.o -o example.so
- </pre></div>
- <H3><a name="Php_nn1_3"></a>32.1.2 Using PHP Extensions</H3>
- <p>
- To test the extension from a PHP script, you need to load it first. You
- can load it for every script by adding this line the <tt>[PHP]</tt> section of
- <tt>php.ini</tt>:
- </p>
- <div class="code"><pre>
- extension=/path/to/modulename.so
- </pre></div>
- <p>
- Alternatively, you can load it explicitly only for scripts which need it
- by adding this line:
- </p>
- <div class="code"><pre>
- dl("/path/to/modulename.so"); // Load the module
- </pre></div>
- <p>
- to the start of each PHP file. SWIG also generates a php module, which
- attempts to do the <tt>dl()</tt> call for you:
- </p>
- <div class="code"><pre>
- include("example.php");
- </pre></div>
- <H2><a name="Php_nn2"></a>32.2 Basic PHP interface</H2>
- <p>
- It is important to understand that PHP uses a single global namespace
- into which all symbols from extension modules are loaded. It is quite
- possible for names of symbols in one extension module to clash with
- other symbols unless care is taken to <tt>%rename</tt> them. At present
- SWIG doesn't have support for the namespace feature added in PHP 5.3.
- </p>
- <H3><a name="Php_nn2_1"></a>32.2.1 Constants</H3>
- <p>
- These work in much the same way as in C/C++. Constants can be defined
- by using either the normal C pre-processor declarations, or the
- <tt>%constant</tt> SWIG directive. These will then be available from
- your PHP script as a PHP constant, (i.e. no dollar sign is needed to
- access them.) For example, with a swig interface file like this,
- </p>
- <div class="code"><pre>
- %module example
- #define PI 3.14159
- %constant int E = 2.71828
- </pre>
- </div>
- <p>
- you can access the constants in your PHP script like this,
- </p>
- <div class="code"><pre>
- include("example.php");
- echo "PI = " . PI . "\n";
- echo "E = " . E . "\n";
- </pre>
- </div>
- <p>
- There's one peculiarity of how constants work in PHP which it is useful
- to note (this is not specific to SWIG though) - if you try to use an undeclared
- constant, PHP will issue a warning and then expand the constant to a string
- version of the constant's name. The warning will often be missed though as
- if you're using PHP in a webserver, it will probably end up in error.log or
- similar.
- </p>
- <p>
- For example,
- </p>
- <div class="code"><pre>
- %module example
- #define EASY_TO_MISPELL 0
- </pre>
- </div>
- <p>
- accessed incorrectly in PHP,
- </p>
- <div class="code">
- <pre>
- include("example.php");
- if(EASY_TO_MISPEL) {
- ....
- } else {
- ....
- }
- </pre>
- </div>
- <p>
- The mis-spelled constant will become the string 'EASY_TO_MISPEL', which
- is treated as true by the if test, when the value of the intended constant
- would be treated as false!
- </p>
- <H3><a name="Php_nn2_2"></a>32.2.2 Global Variables</H3>
- <p>
- Because PHP does not provide a mechanism to intercept access and
- assignment of global variables, global variables are supported through
- the use of automatically generated accessor functions.
- </p>
- <div class="code"><pre>
- %module example;
- %inline %{
- double seki = 2;
- void print_seki() {
- zend_printf("seki is now %f\n",seki);
- }
- %}
- </pre></div>
- <p>
- is accessed as follows:
- </p>
- <div class="code"><pre>
- include("example.php");
- print seki_get();
- seki_set( seki_get() * 2); # The C variable is now 4.
- print seki_get();
- </pre></div>
- <p>
- SWIG supports global variables of all C datatypes including pointers
- and complex objects. Additional types can be supported by using the
- <tt>varinit</tt> typemap.
- </p>
- <p>
- SWIG honors the <tt>%immutable</tt> modifier by not generating code
- for the <tt>_set</tt> method. This provides read-only access to the
- variable from the php script. Attempting to access the <tt>_set</tt>
- method will result in a php fatal error because the function is
- undefined.
- </p>
- <p>
- At this time SWIG does not support custom accessor methods.
- </p>
- <H3><a name="Php_nn2_3"></a>32.2.3 Functions</H3>
- <p>
- C functions are converted into PHP functions. Default/optional arguments are
- also allowed. An interface file like this :
- </p>
- <div class="code"><pre>
- %module example
- int foo(int a);
- double bar(double, double b = 3.0);
- ...
- </pre></div>
- <p>
- Will be accessed in PHP like this :
- </p>
- <div class="code"><pre>
- include("example.php");
- $a = foo(2);
- $b = bar(3.5, -1.5);
- $c = bar(3.5); # Use default argument for 2nd parameter
- </pre></div>
- <!-- This isn't correct for 1.3.30 and needs rewriting to reflect reality
- <p>
- Because PHP is a dynamically typed language, the default typemaps
- used for simple types will attempt to coerce the arguments into the appropriate type. That is the following invocations are equivalent:
- </p>
- <div class="code"><pre>
- $a = foo(2);
- $a = foo("2");
- $a = foo(2.0);
- </pre></div>
- <p>
- Functions are invoked using pass by value semantics like all of PHP.
- This means the conversion which automatically takes place when
- invoking a swig wrapped method does not change the native type of the
- argument variable.
- </p>
- <div class="code"><pre>
- $s = "2 A string representing two";
- $a = foo($s); # invokes 'foo(2)';
- print $s; # The value of $s was not changed.
- </pre></div>
- -->
- <H3><a name="Php_nn2_4"></a>32.2.4 Overloading</H3>
- <p>
- Although PHP does not support overloading functions natively, swig
- will generate dispatch functions which will use <tt>%typecheck</tt>
- typemaps to allow overloading. This dispatch function's operation and
- precedence is described in <a
- href="SWIGPlus.html#SWIGPlus_overloaded_methods">Wrapping
- Overloaded Functions and Methods</a>.
- </p>
- <!-- This isn't correct for 1.3.30 and needs rewriting to reflect reality
- <p>
- Because PHP is a dynamically typed language, simple values can be
- silently converted from one type to another. For example, integers,
- doubles and strings silently convert to each other depending on
- context. This situation make overloading slightly problematic because
- given the following function:
- </p>
- <div class="code"><pre>
- void doit( int i );
- void doit( double i );
- </pre></div>
- <p>
- it is questionable which to invoke when <tt>doit("2");</tt> is used in
- PHP. The string <tt>"2"</tt> simultaneously represents the integer
- <tt>2</tt> and the double <tt>2.0</tt>.
- </p>
- <p>
- In order to provide the most natural experience to PHP programmers,
- the default <tt>%typecheck</tt> implemented in <tt>php.swg</tt>
- allows any simple type (integer, double, string) in PHP to be used for
- any simple C type (int, double, char *). The function selected then
- depends only on the argument type precedence defined by SWIG.
- </p>
- <p>
- It should be noted that <tt>SWIGTYPE</tt> references and pointers will
- not be silently converted. So these two functions:
- </p>
- <div class="code"><pre>
- void doit( const Vector & );
- void doit( int i );
- </pre></div>
- <p>
- Cause less confusion and <tt>doit("2");</tt> will invoke the function
- taking the integer argument.
- </p>
- -->
- <H3><a name="Php_nn2_5"></a>32.2.5 Pointers and References</H3>
- <p>
- Pointers to C/C++ objects are represented
- as PHP resources, rather like MySQL connection handles.
- </p>
- <p>
- There are multiple ways to wrap pointers to simple types. Given the
- following C method:
- </p>
- <div class="code"><pre>
- void add( int *in1, int *in2, int *result);
- </pre></div>
- <p>
- One can include <b>cpointer.i</b> to generate PHP wrappers to <tt>int
- *</tt>.
- </p>
- <div class="code"><pre>
- %module example
- %include "cpointer.i"
- %pointer_functions(int,intp)
- void add( int *in1, int *in2, int *result);
- </pre></div>
- <p>
- This will result in the following usage in PHP:
- </p>
- <div class="code"><pre>
- <?php
- include("example.php");
- $in1=copy_intp(3);
- $in2=copy_intp(5);
- $result=new_intp();
- add( $in1, $in2, $result );
- echo "The sum " . intp_value($in1) . " + " . intp_value($in2) . " = " . intp_value( $result) . "\n";
- ?>
- </pre></div>
- <p>
- An alternative would be to use the include <b>typemaps.i</b> which
- defines named typemaps for INPUT, OUTPUT and INOUT variables. One
- needs to either <tt>%apply</tt> the appropriate typemap or adjust the
- parameter names as appropriate.
- </p>
- <div class="code"><pre>
- %module example
- %include "typemaps.i"
- void add( int *INPUT, int *INPUT, int *OUTPUT);
- </pre></div>
- <p>
- This will result in the following usage in PHP:
- </p>
- <div class="code"><pre>
- <?php
- include("example.php");
- $in1 = 3;
- $in2 = 5;
- $result= add($in1,$in2); # Note using variables for the input is unnecessary.
- echo "The sum $in1 + $in2 = $result\n";
- ?>
- </pre></div>
- <p>
- Because PHP has a native concept of reference, it may seem more natural
- to the PHP developer to use references to pass pointers. To enable
- this, one needs to include <b>phppointers.i</b> which defines the
- named typemap REFERENCE.
- </p>
- <div class="code"><pre>
- %module example
- %include "phppointers.i"
- void add( int *REF, int *REF, int *REF);
- </pre></div>
- <p>
- This will result in the following usage in PHP:
- </p>
- <div class="code"><pre>
- <?php
- include("example.php");
- $in1 = 3;
- $in2 = 5;
- $result = 0;
- add(&$in1,&$in2,&$result);
- echo "The sum $in1 + $in2 = $result\n";
- ?>
- </pre></div>
- <p>
- It is important to note that a php variable which is NULL when passed
- by reference would end up passing a NULL pointer into the function.
- In PHP, an unassigned variable (i.e. where the first reference to the
- variable is not an assignment) is
- NULL. In the above example, if any of the three variables had not
- been assigned, a NULL pointer would have been passed into
- <tt>add</tt>. Depending on the implementation of the function, this
- may or may not be a good thing.
- </p>
- <p>
- We chose to allow passing NULL pointers into functions because that is
- sometimes required in C libraries. A NULL pointer can be created in
- PHP in a number of ways: by using <tt>unset</tt> on an existing
- variable, or assigning <tt>NULL</tt> to a variable.
- </p>
- <H3><a name="Php_nn2_6"></a>32.2.6 Structures and C++ classes</H3>
- <p>
- SWIG defaults to wrapping C++ structs and classes with PHP classes - this
- is done by generating a PHP wrapper script which defines proxy classes
- which calls a set of flat functions which actually wrap the C++ class.
- You can disable this wrapper layer by passing the command-line option
- "-noproxy" in which case you'll just get the flat functions.
- </p>
- <p>
- This interface file
- </p>
- <div class="code"><pre>
- %module vector
- class Vector {
- public:
- double x,y,z;
- Vector();
- ~Vector();
- double magnitude();
- };
- struct Complex {
- double re, im;
- };
- </pre></div>
- <p>
- Would be used in the following way from PHP5:
- </p>
- <div class="code"><pre>
- <?php
- require "vector.php";
- $v = new Vector();
- $v->x = 3;
- $v->y = 4;
- $v->z = 5;
- echo "Magnitude of ($v->x,$v->y,$v->z) = " . $v->magnitude() . "\n";
- $v = NULL; # destructor called.
- $c = new Complex();
- $c->re = 0;
- $c->im = 0;
- # $c destructor called when $c goes out of scope.
- ?>
- </pre></div>
- <p>
- Member variables and methods are accessed using the <tt>-></tt> operator.
- </p>
- <H4><a name="Php_nn2_6_1"></a>32.2.6.1 Using <tt>-noproxy</tt></H4>
- <p>
- The <tt>-noproxy</tt> option flattens the object structure and
- generates collections of named functions (these are the functions
- which the PHP5 class wrappers call). The above example results
- in the following PHP functions:
- </p>
- <div class="code"><pre>
- new_Vector();
- Vector_x_set($obj,$d);
- Vector_x_get($obj);
- Vector_y_set($obj,$d);
- Vector_y_get($obj);
- Vector_z_set($obj,$d);
- Vector_z_get($obj);
- Vector_magnitude($obj);
- new_Complex();
- Complex_re_set($obj,$d);
- Complex_re_get($obj);
- Complex_im_set($obj,$d);
- Complex_im_get($obj);
- </pre></div>
- <H4><a name="Php_nn2_6_2"></a>32.2.6.2 Constructors and Destructors</H4>
- <p>
- The constructor is called when <tt>new Object()</tt> (or
- <tt>new_Object()</tt> if using <tt>-noproxy</tt>) is used to create an
- instance of the object. If multiple constructors are defined for an
- object, function overloading will be used to determine which
- constructor to execute.
- </p>
- <p>
- Because PHP uses reference counting to manage resources, simple
- assignment of one variable to another such as:
- </p>
- <div class="code"><pre>
- $ref = $v;
- </pre></div>
- <p>
- causes the symbol <tt>$ref</tt> to refer to the same underlying object
- as <tt>$v</tt>. This does not result in a call to the C++ copy
- constructor or copy assignment operator.
- </p>
- <p>
- One can force execution of the copy constructor by using:
- </p>
- <div class="code"><pre>
- $o_copy = new Object($o);
- </pre></div>
- <p>
- Destructors are automatically called when all variables referencing
- the instance are reassigned or go out of scope. The destructor is not
- available to be called manually. To force a destructor to be called
- the programmer can either reassign the variable or call
- <tt>unset($v)</tt>
- </p>
- <H4><a name="Php_nn2_6_3"></a>32.2.6.3 Static Member Variables</H4>
- <p>
- Static member variables in C++ are not wrapped as such in PHP
- as it does not appear to be possible to intercept accesses to such variables.
- Therefore, static member variables are
- wrapped using a class function with the same name, which
- returns the current value of the class variable. For example
- </p>
- <div class="code"><pre>
- %module example
- class Ko {
- static int threats;
- };
- </pre></div>
- <p>
- would be accessed in PHP as,
- </p>
- <div class="code"><pre>
- include("example.php");
- echo "There has now been " . Ko::threats() . " threats\n";
- </pre></div>
- <p>
- To set the static member variable, pass the value as the argument to the class
- function, e.g.
- </p>
- <div class="code"><pre>
- Ko::threats(10);
- echo "There has now been " . Ko::threats() . " threats\n";
- </pre></div>
- <H4><a name="Php_nn2_6_4"></a>32.2.6.4 Static Member Functions</H4>
- <p>
- Static member functions are supported in PHP using the
- <tt>class::function()</tt> syntax. For example
- </p>
- <div class="code"><pre>
- %module example
- class Ko {
- static void threats();
- };
- </pre></div>
- would be executed in PHP as,
- <div class="code"><pre>
- include("example.php");
- Ko::threats();
- </pre></div>
- <H3><a name="Php_nn2_7"></a>32.2.7 PHP Pragmas, Startup and Shutdown code</H3>
- <p>
- To place PHP code in the generated "example.php" file one can use the
- <b>code</b> pragma. The code is inserted after loading the shared
- object.
- </p>
- <div class="code"><pre>
- %module example
- %pragma(php) code="
- # This code is inserted into example.php
- echo \"example.php execution\\n\";
- "
- </pre></div>
- <p>
- Results in the following in "example.php"
- </p>
- <div class="code"><pre>
- # This code is inserted into example.php
- echo "example.php execution\n";
- </pre></div>
- <p>
- The <b>include</b> pragma is a short cut to add include statements to
- the example.php file.
- </p>
- <div class="code"><pre>
- %module example
- %pragma(php) code="
- include \"include.php\";
- "
- %pragma(php) include="include.php" // equivalent.
- </pre></div>
- <p>
- The <b>phpinfo</b> pragma inserts code in the
- <tt>PHP_MINFO_FUNCTION</tt> which is called from PHP's
- phpinfo() function.
- </p>
- <div class="code"><pre>
- %module example;
- %pragma(php) phpinfo="
- zend_printf("An example of PHP support through SWIG\n");
- php_info_print_table_start();
- php_info_print_table_header(2, \"Directive\", \"Value\");
- php_info_print_table_row(2, \"Example support\", \"enabled\");
- php_info_print_table_end();
- "
- </pre></div>
- <p>
- To insert code into the <tt>PHP_MINIT_FUNCTION</tt>, one can use
- either <tt>%init</tt> or <tt>%minit</tt>.
- </p>
- <div class="code"><pre>
- %module example;
- %init {
- zend_printf("Inserted into PHP_MINIT_FUNCTION\n");
- }
- %minit {
- zend_printf("Inserted into PHP_MINIT_FUNCTION\n");
- }
- </pre></div>
- <p>
- To insert code into the <tt>PHP_MSHUTDOWN_FUNCTION</tt>, one can use
- either <tt>%shutdown</tt> or <tt>%mshutdown</tt>.
- </p>
- <div class="code"><pre>
- %module example;
- %mshutdown {
- zend_printf("Inserted into PHP_MSHUTDOWN_FUNCTION\n");
- }
- </pre></div>
- <p>
- The <tt>%rinit</tt> and <tt>%rshutdown</tt> statements are very similar but insert code
- into the request init (PHP_RINIT_FUNCTION) and request shutdown (PHP_RSHUTDOWN_FUNCTION) code respectively.
- </p>
- <H2><a name="Php_nn3"></a>32.3 Cross language polymorphism</H2>
- <p>
- Proxy classes provide a more natural, object-oriented way to access
- extension classes. As described above, each proxy instance has an
- associated C++ instance, and method calls to the proxy are passed to the
- C++ instance transparently via C wrapper functions.
- </p>
- <p>
- This arrangement is asymmetric in the sense that no corresponding
- mechanism exists to pass method calls down the inheritance chain from
- C++ to PHP. In particular, if a C++ class has been extended in PHP
- (by extending the proxy class), these extensions will not be visible
- from C++ code. Virtual method calls from C++ are thus not able access
- the lowest implementation in the inheritance chain.
- </p>
- <p>
- Changes have been made to SWIG 1.3.18 to address this problem and make
- the relationship between C++ classes and proxy classes more symmetric.
- To achieve this goal, new classes called directors are introduced at the
- bottom of the C++ inheritance chain. Support for generating PHP classes
- has been added in SWIG 1.3.40. The job of the directors is to route
- method calls correctly, either to C++ implementations higher in the
- inheritance chain or to PHP implementations lower in the inheritance
- chain. The upshot is that C++ classes can be extended in PHP and from
- C++ these extensions look exactly like native C++ classes. Neither C++
- code nor PHP code needs to know where a particular method is
- implemented: the combination of proxy classes, director classes, and C
- wrapper functions takes care of all the cross-language method routing
- transparently.
- </p>
- <H3><a name="Php_nn3_1"></a>32.3.1 Enabling directors</H3>
- <p>
- The director feature is disabled by default. To use directors you
- must make two changes to the interface file. First, add the "directors"
- option to the %module directive, like this:
- </p>
- <div class="code">
- <pre>
- %module(directors="1") modulename
- </pre>
- </div>
- <p>
- Without this option no director code will be generated. Second, you
- must use the %feature("director") directive to tell SWIG which classes
- and methods should get directors. The %feature directive can be applied
- globally, to specific classes, and to specific methods, like this:
- </p>
- <div class="code">
- <pre>
- // generate directors for all classes that have virtual methods
- %feature("director");
- // generate directors for all virtual methods in class Foo
- %feature("director") Foo;
- // generate a director for just Foo::bar()
- %feature("director") Foo::bar;
- </pre>
- </div>
- <p>
- You can use the %feature("nodirector") directive to turn off
- directors for specific classes or methods. So for example,
- </p>
- <div class="code">
- <pre>
- %feature("director") Foo;
- %feature("nodirector") Foo::bar;
- </pre>
- </div>
- <p>
- will generate directors for all virtual methods of class Foo except
- bar().
- </p>
- <p>
- Directors can also be generated implicitly through inheritance.
- In the following, class Bar will get a director class that handles
- the methods one() and two() (but not three()):
- </p>
- <div class="code">
- <pre>
- %feature("director") Foo;
- class Foo {
- public:
- Foo(int foo);
- virtual void one();
- virtual void two();
- };
- class Bar: public Foo {
- public:
- virtual void three();
- };
- </pre>
- </div>
- <p>
- then at the PHP side you can define
- </p>
- <div class="targetlang">
- <pre>
- require("mymodule.php");
- class MyFoo extends Foo {
- function one() {
- print "one from php\n";
- }
- }
- </pre>
- </div>
- <H3><a name="Php_nn3_2"></a>32.3.2 Director classes</H3>
-
- <p>
- For each class that has directors enabled, SWIG generates a new class
- that derives from both the class in question and a special
- <tt>Swig::Director</tt> class. These new classes, referred to as director
- classes, can be loosely thought of as the C++ equivalent of the PHP
- proxy classes. The director classes store a pointer to their underlying
- PHP object. Indeed, this is quite similar to the "_cPtr" and "thisown"
- members of the PHP proxy classes.
- </p>
- <p>
- For simplicity let's ignore the <tt>Swig::Director</tt> class and refer to the
- original C++ class as the director's base class. By default, a director
- class extends all virtual methods in the inheritance chain of its base
- class (see the preceding section for how to modify this behavior).
- Thus all virtual method calls, whether they originate in C++ or in
- PHP via proxy classes, eventually end up in at the implementation in the
- director class. The job of the director methods is to route these method
- calls to the appropriate place in the inheritance chain. By "appropriate
- place" we mean the method that would have been called if the C++ base
- class and its extensions in PHP were seamlessly integrated. That
- seamless integration is exactly what the director classes provide,
- transparently skipping over all the messy extension API glue that binds
- the two languages together.
- </p>
- <p>
- In reality, the "appropriate place" is one of only two possibilities:
- C++ or PHP. Once this decision is made, the rest is fairly easy. If the
- correct implementation is in C++, then the lowest implementation of the
- method in the C++ inheritance chain is called explicitly. If the correct
- implementation is in PHP, the Zend API is used to call the method of the
- underlying PHP object (after which the usual virtual method resolution
- in PHP automatically finds the right implementation).
- </p>
- <p>
- Now how does the director decide which language should handle the method call?
- The basic rule is to handle the method in PHP, unless there's a good
- reason not to. The reason for this is simple: PHP has the most
- "extended" implementation of the method. This assertion is guaranteed,
- since at a minimum the PHP proxy class implements the method. If the
- method in question has been extended by a class derived from the proxy
- class, that extended implementation will execute exactly as it should.
- If not, the proxy class will route the method call into a C wrapper
- function, expecting that the method will be resolved in C++. The wrapper
- will call the virtual method of the C++ instance, and since the director
- extends this the call will end up right back in the director method. Now
- comes the "good reason not to" part. If the director method were to blindly
- call the PHP method again, it would get stuck in an infinite loop. We avoid this
- situation by adding special code to the C wrapper function that tells
- the director method to not do this. The C wrapper function compares the
- called and the declaring class name of the given method. If these are
- not the same, then the C wrapper function tells the director to resolve
- the method by calling up the C++ inheritance chain, preventing an
- infinite loop.
- </p>
- <p>
- One more point needs to be made about the relationship between director
- classes and proxy classes. When a proxy class instance is created in
- PHP, SWIG creates an instance of the original C++ class and assigns it
- to <tt>->_cPtr</tt>. This is exactly what happens without directors
- and is true even if directors are enabled for the particular class in
- question. When a class <i>derived</i> from a proxy class is created,
- however, SWIG then creates an instance of the corresponding C++ director
- class. The reason for this difference is that user-defined subclasses
- may override or extend methods of the original class, so the director
- class is needed to route calls to these methods correctly. For
- unmodified proxy classes, all methods are ultimately implemented in C++
- so there is no need for the extra overhead involved with routing the
- calls through PHP.
- </p>
- <H3><a name="Php_nn3_3"></a>32.3.3 Ownership and object destruction</H3>
- <p>
- Memory management issues are slightly more complicated with directors
- than for proxy classes alone. PHP instances hold a pointer to the
- associated C++ director object, and the director in turn holds a pointer
- back to the PHP object. By default, proxy classes own their C++ director
- object and take care of deleting it when they are garbage collected.
- </p>
- <p>
- This relationship can be reversed by calling the special
- <tt>->thisown</tt> property of the proxy class. After setting this
- property to <tt>0</tt>, the director class no longer destroys the PHP
- object. Assuming no outstanding references to the PHP object remain,
- the PHP object will be destroyed at the same time. This is a good thing,
- since directors and proxies refer to each other and so must be created
- and destroyed together. Destroying one without destroying the other will
- likely cause your program to segfault.
- </p>
- <p>
- Here is an example:
- </p>
- <div class="code">
- <pre>
- class Foo {
- public:
- ...
- };
- class FooContainer {
- public:
- void addFoo(Foo *);
- ...
- };
- </pre>
- </div>
- <br>
- <div class="targetlang">
- <pre>
- $c = new FooContainer();
- $a = new Foo();
- $a->thisown = 0;
- $c->addFoo($a);
- </pre>
- </div>
- <p>
- In this example, we are assuming that FooContainer will take care of
- deleting all the Foo pointers it contains at some point.
- </p>
- <H3><a name="Php_nn3_4"></a>32.3.4 Exception unrolling</H3>
- <p>
- With directors routing method calls to PHP, and proxies routing them
- to C++, the handling of exceptions is an important concern. By default, the
- directors ignore exceptions that occur during method calls that are
- resolved in PHP. To handle such exceptions correctly, it is necessary
- to temporarily translate them into C++ exceptions. This can be done with
- the %feature("director:except") directive. The following code should
- suffice in most cases:
- </p>
- <div class="code">
- <pre>
- %feature("director:except") {
- if ($error == FAILURE) {
- throw Swig::DirectorMethodException();
- }
- }
- </pre>
- </div>
- <p>
- This code will check the PHP error state after each method call from a
- director into PHP, and throw a C++ exception if an error occurred. This
- exception can be caught in C++ to implement an error handler.
- Currently no information about the PHP error is stored in the
- Swig::DirectorMethodException object, but this will likely change in the
- future.
- </p>
- <p>
- It may be the case that a method call originates in PHP, travels up to
- C++ through a proxy class, and then back into PHP via a director method.
- If an exception occurs in PHP at this point, it would be nice for that
- exception to find its way back to the original caller. This can be done
- by combining a normal %exception directive with the
- <tt>director:except</tt> handler shown above. Here is an example of a
- suitable exception handler:
- </p>
- <div class="code">
- <pre>
- %exception {
- try { $action }
- catch (Swig::DirectorException &e) { SWIG_fail; }
- }
- </pre>
- </div>
- <p>
- The class Swig::DirectorException used in this example is actually a
- base class of Swig::DirectorMethodException, so it will trap this
- exception. Because the PHP error state is still set when
- Swig::DirectorMethodException is thrown, PHP will register the exception
- as soon as the C wrapper function returns.
- </p>
- <H3><a name="Php_nn3_5"></a>32.3.5 Overhead and code bloat</H3>
- <p>
- Enabling directors for a class will generate a new director method for
- every virtual method in the class' inheritance chain. This alone can
- generate a lot of code bloat for large hierarchies. Method arguments
- that require complex conversions to and from target language types can
- result in large director methods. For this reason it is recommended that
- you selectively enable directors only for specific classes that are
- likely to be extended in PHP and used in C++.
- </p>
- <p>
- Compared to classes that do not use directors, the call routing in the
- director methods does add some overhead. In particular, at least one
- dynamic cast and one extra function call occurs per method call from
- PHP. Relative to the speed of PHP execution this is probably completely
- negligible. For worst case routing, a method call that ultimately
- resolves in C++ may take one extra detour through PHP in order to ensure
- that the method does not have an extended PHP implementation. This could
- result in a noticeable overhead in some cases.
- </p>
- <p>
- Although directors make it natural to mix native C++ objects with PHP
- objects (as director objects) via a common base class pointer, one
- should be aware of the obvious fact that method calls to PHP objects
- will be much slower than calls to C++ objects. This situation can be
- optimized by selectively enabling director methods (using the %feature
- directive) for only those methods that are likely to be extended in PHP.
- </p>
- <H3><a name="Php_nn3_6"></a>32.3.6 Typemaps</H3>
- <p>
- Typemaps for input and output of most of the basic types from director
- classes have been written. These are roughly the reverse of the usual
- input and output typemaps used by the wrapper code. The typemap
- operation names are 'directorin', 'directorout', and 'directorargout'.
- The director code does not currently use any of the other kinds of
- typemaps. It is not clear at this point which kinds are appropriate and
- need to be supported.
- </p>
- <H3><a name="Php_nn3_7"></a>32.3.7 Miscellaneous</H3>
- <p> Director typemaps for STL classes are mostly in place, and hence you
- should be able to use std::string, etc., as you would any other type.
- </p>
- </body>
- </html>