swig/Doc/Manual/Php.html
Dave Beazley 12a43edc2d The great merge
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@4141 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2002-11-30 22:01:28 +00:00

496 lines
No EOL
18 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- Hand crafted HTML -->
<html>
<head>
<title>SWIG and PHP4</title>
</head>
<body bgcolor="#ffffff">
<a name="n1"></a><H1>18 SWIG and PHP4</H1>
<!-- INDEX -->
<ul>
<li><a href="#n2">Preliminaries</a>
<li><a href="#n3">Building PHP4 Extensions</a>
<ul>
<li><a href="#n4">Building a loadable extension</a>
<li><a href="#n5">Basic PHP4 interface</a>
<li><a href="#n6">Functions</a>
<li><a href="#n7">Global Variables</a>
<li><a href="#n8">Pointers </a>
<li><a href="#n9">Structures and C++ classes</a>
<li><a href="#n10">Constants</a>
<li><a href="#n11">Shadow classes</a>
<li><a href="#n12">Constructors and Destructers</a>
<li><a href="#n13">Static Member Variables</a>
<li><a href="#n14">PHP4 Pragmas</a>
<li><a href="#n15">Building extensions into php</a>
<li><a href="#n16">To be furthered...</a>
</ul>
</ul>
<!-- INDEX -->
<b>Caution: This chapter (and module!) is still under construction</b>
In this chapter, we discuss SWIG's support of PHP4. The PHP4 module is
still under development so some of the features below may not work properly
(or at all!.)
<p>
The PHP4 module has undergone a lot of changes recently affecting the
way shadow classes are implemented so you should read this document even
if you thought you were familiar with what it said. The major change is
that shadow classes are implemented inside the php module in C++ instead
of in the generated .php file in php.
<a name="n2"></a><H2>18.1 Preliminaries</H2>
In order to use this module, you will need to have a copy of the PHP 4.0 (or
above) include files to compile the SWIG generated files. You can find these
files by running <tt>'php-config --includes'</tt>. To test the modules you will
need either the php binary or the Apache php module. If you want to build your
extension into php directly (without having the overhead of loading it into
each script), you will need the complete PHP source tree available.
<a name="n3"></a><H2>18.2 Building PHP4 Extensions</H2>
To build a PHP4 extension, run swig using the <tt>-php4</tt> option as follows :
<p>
<blockquote><pre>
swig -php4 example.i
</pre></blockquote>
This will produce 3 files by default. The first file, <tt>example_wrap.c</tt>
contains all of the C code needed to build a PHP4 extension. The second file,
<tt>php_example.h</tt> contains the header information needed to link the
extension into PHP. The third file, <tt>example.php</tt> can be included by
your php scripts. It will attempt to dynamically load your extension, and is
a place-holder for extra code specified in the interface file. If you want to
build your extension using the <tt>phpize</tt> utility, or if you want to
build your module into PHP directly, you can specify the <tt>-phpfull</tt>
command line argument to swig.
<p>
The <tt>-phpfull</tt> will generate three extra files.
The first extra file, <tt>config.m4</tt> contains the shell code needed to
enable the extension as part of the PHP4 build process. The second extra file,
<tt>Makefile.in</tt> contains the information needed to build the final
Makefile after substitutions. The third and final extra file, <tt>CREDITS</tt>
should contain the credits for the extension.
<p>
To finish building the extension, you have two choices. You can either build
the extension as a seperate object file which will then have to be explicitly
loaded by each script. Or you can rebuild the entire php source tree and build
the extension into the php executable/library so it will be available in every
script. The first choice is the default, however it can be changed by passing
the '-phpfull' command line switch to select the second build method.
<a name="n4"></a><H3>18.2.1 Building a loadable extension</H3>
To build a dynamic module for PHP, you have two options. You can use the
<tt>phpize</tt> utility, or you can do it manually.
<p>
To build manually, use a compile string similar to this (different for each
OS):
<blockquote><pre>
cc -I.. $(PHPINC) -fpic -c example_wrap.c
cc -shared example_wrap.o -o libexample.so
</pre></blockquote>
<p>
To build with phpize, after you have run swig you will need
to run the 'phpize' command (installed as part of php) in the same
directory. This re-creates the php build environment in that directory. It also
creates a configure file which includes the shell code from the config.m4 that
was generated by SWIG, this configure script will accept a command line argument
to enable the extension to be run ( by default the command line argument is
--enable-modulename, however you can edit the config.m4 file before running
phpize to accept --with-modulename. You can also add extra tests in config.m4
to check that a correct library version is installed or correct header files
are included, etc, but you must edit this file before running phpize. )
If you like SWIG can generate simple extra tests for libraries and header
files for you.
<blockquote><pre>
swig -php4 -phpfull -withlibs "xapian omquery" --withincs "om.h"
</pre></blockquote>
<p>
Will include in the config.m4 search for libxapian.a or libxapian.so and
search for libomquery.a or libomquery.so as well as a search for om.h
<p>
If you depend on source files not generated by SWIG, before generated
configure file, you may need to edit the <tt>
Makefile.in</tt> file. This contains the names of the source files to compile
(just the wrapper file by default) and any additional libraries needed to be
linked in. If there are extra C files to compile, you will need to add them
to the Makefile.in, or add the names of libraries if they are needed. In
simple cases SWIG is pretty good at generating a complete Makefile.in and
config.m4 which need no further editing. <p>
You then run the configure script with the command line argument needed
to enable the extension. Then run make, which builds the extension.
The extension object file will be left in the modules sub directory, you can
move it to wherever it is convenient to call from your php script.
<p>
<p>
To test the extension from a PHP script, you need to load it first. You do
this by putting the line,
<blockquote><pre>
dl("/path/to/modulename.so"); // Load the module
</pre></blockquote>
at the start of each PHP file. SWIG also generates a php module, which
attempts to do the <tt>dl()</tt> call for you:
<blockquote><pre>
include("example.php");
</pre></blockquote>
A more complicated method which builds the module directly into the <tt>php</tt>
executable is described <a href="n12">below</a>.
<a name="n5"></a><H3>18.2.2 Basic PHP4 interface</H3>
<a name="n6"></a><H3>18.2.3 Functions</H3>
C functions are converted into PHP functions. Default/optional arguments are
also allowed. An interface file like this :<p>
<p>
<blockquote><pre>%module default
int foo(int a);
double bar(double, double b = 3.0);
...
</pre></blockquote>
Will be accessed in PHP like this :<p>
<p>
<blockquote><pre>
dl("default.so"); $a = foo(2);
$b = bar(3.5, -1.5);
$c = bar(3.5); # Use default argument for 2nd parameter
</pre></blockquote>
<a name="n7"></a><H3>18.2.4 Global Variables</H3>
Global variables are difficult for PHP to handle, unlike Perl, their is no
'magic' way to intercept modifications made to variables, so changes in a PHP
variable will not be reflected in its C equivalent. To get around the problem,
two extra function are generated, <tt>Swig_sync_c()</tt> and <tt>Swig_sync_php()</tt>. These functions are called at the start and end of every function call,
ensuring changes made in PHP are updated in C ( and vice versa. ) Because this
is handled for you, you can modify the variables in PHP as normal, e.g.
<p><p>
<blockquote><pre>%module example;
...
double seki = 2;
...
int example_func(void);
</pre></blockquote>
is accessed as follow :<p>
<p>
<blockquote><pre>
dl("example.so");
print $seki;
$seki = $seki * 2; # Does not affect C variable, still equal to 2
example_func(); # Syncs C variable to PHP Variable, now both 4
<pre></blockquote>
SWIG supports global variables of all C datatypes including pointers and complex
objects.<p>
<a name="n8"></a><H3>18.2.5 Pointers </H3>
Pointers to C/C++ objects <b>no longer</b> represented as character
strings such as:<tt>_523d3f4_Circle_p</tt>, instead they are represented
as PHP resources, rather like MySQL connection handles.
<p>
You can also explicitly create a NULL pointer as a string "NULL"
or by passing a null or empty value.
<a name="n9"></a><H3>18.2.6 Structures and C++ classes</H3>
For structures and classes, SWIG produces accessor fuction for each member function and data. For example :<p>
<p>
<blockquote><pre>%module vector
class Vector {
public:
double x,y,z;
Vector();
~Vector();
double magnitude();
};
</pre></blockquote>
This gets turned into the following collection of PHP functions :<p>
<blockquote><pre>
Vector_x_set($obj);
Vector_x_get($obj);
Vector_y_set($obj);
Vector_y_get($obj);
Vector_z_set($obj);
Vector_z_get($obj);
new_Vector();
delete_Vector($obj);
Vector_magnitude($obj);
</pre></blockquote>
To use the class, simply use these functions. However, SWIG also has a mechanism
for creating shadow classes that hides these functions and uses an object
oriented interface instead - see <a href="n7">below</a>
<a name="n10"></a><H3>18.2.7 Constants</H3>
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,
(e.g. no dollar sign is needed to access them. ) For example, with a swig file like this,
<p>
<blockquote><pre>
%module example
#define PI 3.14159
%constant int E = 2.71828
</pre>
</blockquote>
<p>
you can access from in your php script like this,
<blockquote><pre>
dl("libexample.so");
echo "PI = " . PI . "\n";
echo "E = " . E . "\n";
</pre>
</blockquote>
<p>
There are two peculiarities with using constants in PHP4. The first is that
if you try to use an undeclared constant, it will evaulate to a string
set to the constants name. For example,
<p>
<blockquote><pre>
%module example
#define EASY_TO_MISPELL 0
</pre>
</blockquote>
accessed incorrectly in PHP,
<p>
<blockquote>
<pre>
dl("libexample.so");
if(EASY_TO_MISPEL) {
....
} else {
....
}
</pre>
</blockquote>
<p>
will issue a warning about the undeclared constant, but will then evalute
it and turn it into a string ('EASY_TO_MISPEL'), which evaluates to true,
rather than the value of the constant which would be false. This is a feature.
<p>
The second 'feature' is that although constants are case sensitive (by default),
you cannot declare a constant twice with alternative cases. E.g.,
<p>
<blockquote>
<pre>
%module example
#define TEST Hello
#define Test World
</pre>
</blockquote>
accessed from PHP,
<p>
<pre>
<blockquote>
dl("libexample.so");
echo TEST, Test;
</blockquote>
</pre>
<p>
will output "Hello Test" rather than "Hello World". This is because internally,
all constants are stored in a hash table by their lower case name, so 'TEST' and
'Test' will map to the same hash element ('Test'). But, because we declared them case sensitive, the Zend engine will test if the case matches with the case the
constant was declared with first.
<p>
So, in the example above, the TEST constant was declared first, and will be stored under the hash element 'test'. The 'Test' constant will also map to the same hash element 'test', but will not overwrite it. When called from the script, the TEST constant will again be mapped to the hash element 'test' so the constant will be retrieved. The case will then be checked, and will match up, so the value ('Hello') will be returned. When 'Test' is evaulated, it will also map to the same hash element 'test'. The same constant will be retrieved, this time though the case check will fail as 'Test' != 'TEST'. So PHP will assume that Test is a undeclared constant, and as explained above, will return it as a string set to the constant name ('Test'). Hence the script above will print 'Hello Test'. If
they were declared non-case sensitive, the output would be 'Hello Hello', as
both point to the same value, without the case test taking place.
( Apologies, this paragraph needs rewritting to make some sense. )
</pre>
</blockquote>
<a name="n11"></a><H3>18.2.8 Shadow classes</H3>
To avoid having to call the various accessor function to get at structures or
class members, we can turn C structs and C++ classes into PHP classes that
can be be used directly in PHP scripts as objects and object methods. This is done by writing additional PHP code that builds PHP classes on top of the low-level SWIG interface. These PHP classes "shadow" an underlying C/C++ class.
To have SWIG create shadow classes, use the <tt>-shadow</tt> option :
<p><p><blockquote><pre>% swig -php4 -shadow tbc.i
</pre></blockquote>
<p>
This will produce the same files as before except that the final module
will declare internal PHP classes with the same names as the classes in
your .i file. No longer are the shadow classes defined in
the <tt>.php</tt> file, it will not contain significantly more support PHP
code.
For the most part, the code is the same except that we can now access members of
complex data structures using <tt>-&gt;</tt> instead of the low level access or
functions like before.
.... ( more examples on the way ) ....
<a name="n12"></a><H3>18.2.9 Constructors and Destructers</H3>
Constructors are used in PHP as in C++, they are called when the object is
created and any arguments are passed to them. However, function overloading
is not allowed in PHP so only one constructor can be used. This creates a
problem when copying objects, as we cannot avoid creating a whole new one
when all we want is to make it point to the same value as the original. This
is currently worked around by doing the following,
<ul>
<li>Create the new PHP object
<li>Delete the PHP objects pointer to the C object
<li>Set the PHP object's pointer to the same as the original PHP object's pointer.
</ul>
This is rather convoluted and hopefully will be improved upon in a later
release.
<p><p>
Because the internal wrapped objects are wrapped in PHP resources, PHP
handles the cleaning up when there are no more references to the wrapped
object. 'RegisterShutdownFunction' is no longer needed for this.
I am not sure if PHP resources are all freed at the end of a script, or
when they each go out of scope.
<a name="n13"></a><H3>18.2.10 Static Member Variables</H3>
Class variables are not supported in PHP, however class functions are, using
'::' syntax. Static member variables are therefore accessed using a class
function with the same name, which returns the current value of the class variable. For example
<blockquote><pre>
%module example
class Ko {
static int threats;
...
};
</pre></blockquote>
<p>
would be accessed in PHP as,
<blockquote><pre>
dl("libexample.so");
echo "There has now been " . Ko::threats() . " threats\n";
</pre></blockquote>
To set the static member variable, pass the value as the argument to the class function, e.g.
<blockquote><pre>
Ko::threats(10);
echo "There has now been " . Ko::threats() . " threats\n";
</pre></blockquote>
<a name="n14"></a><H3>18.2.11 PHP4 Pragmas</H3>
There are a few pragmas understood by the PHP4 module. The first,
<b>include</b> adds a file to be included by the generated PHP module. The
second, <b>code</b> adds literal code to the generated PHP module. The third,
<b>phpinfo</b> inserts code to the function called when PHP's phpinfo()
function is called.
<blockquote><pre>
/* example.i */
%pragma(php4) include="foo.php"
%pragma(php4) code="
function foo($bar) {
/* do something */
}
"
%pragma(php4) 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();
"
%include "example.h"
</pre></blockquote>
<a name="n15"></a><H3>18.2.12 Building extensions into php</H3>
This method, selected with the <tt>-phpfull</tt> command line switch, involves
rebuilding the entire php source tree. Whilst more complicated to build,
it does mean that the extension is then available without having to load it
in each script.
<p>
After running swig with the -phpfull switch, you will be left with a shockingly
similiar set of files to the previous build process. However you will then need
to move these files to a subdirectory within the php source tree, this subdirectory you will need to create under the ext directory, with the name of the extension ( e.g mkdir php-4.0.6/ext/modulename .)
<p>
After moving the files into this directory, you will need to run the 'buildall'
script in the php source directory. This rebuilds the configure script
and includes the extra command line arguments from the module you have added.
<p>
Before running the generated configure file, you may need to edit the <tt>
Makefile.in</tt>. This contains the names of the source files to compile (
just the wrapper file by default) and any additional libraries needed to
link in. If their are extra C files to compile you will need to add them
to the Makefile, or add the names of libraries if they are needed.
In most cases <tt>Makefile.in</tt> will be complete, especially if you
make use of <tt>-withlibs</tt> and <tt>-withincs</tt>
<blockquote><pre>
swig -php4 -phpfull -withlibs "xapian omquery" --withincs "om.h"
</pre></blockquote>
<p>
Will include in the config.m4 and Makefile.in search for libxapian.a or
libxapian.so and search for libomquery.a or libomquery.so as well as a
search for om.h
<p>
You then need to run the configure command and pass the necessary command
line arguments to enable your module ( by default this is --enable-modulename,
but this can be changed by editing the config.m4 file in the modules directory
before running the buildall script. In addition, extra tests can be added to
the config.m4 file to ensure the correct libraries and header files are
installed.)
<p>
Once configure has completed, you can run make to build php. If this all
compiles correctly, you should end up with a php executable/library
which contains your new module. You can test it with a php script which
does not have the 'dl' command as used above.
<a name="n16"></a><H3>18.2.13 To be furthered...</H3>
</body>
</html>