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.
This will produce 3 files by default. The first file, example_wrap.c contains all of the C code needed to build a PHP4 extension. The second file, php_example.h contains the header information needed to link the extension into PHP. The third file, example.php 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 phpize utility, or if you want to build your module into PHP directly, you can specify the -phpfull command line argument to swig.swig -php4 example.i
The -phpfull will generate three extra files. The first extra file, config.m4 contains the shell code needed to enable the extension as part of the PHP4 build process. The second extra file, Makefile.in contains the information needed to build the final Makefile after substitutions. The third and final extra file, CREDITS should contain the credits for the extension.
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.
To build manually, use a compile string similar to this (different for each OS):
cc -I.. $(PHPINC) -fpic -c example_wrap.c cc -shared example_wrap.o -o libexample.so
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.
swig -php4 -phpfull -withlibs "xapian omquery" --withincs "om.h"
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
If you depend on source files not generated by SWIG, before generated configure file, you may need to edit the Makefile.in 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.
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.
To test the extension from a PHP script, you need to load it first. You do this by putting the line,
at the start of each PHP file. SWIG also generates a php module, which attempts to do the dl() call for you:dl("/path/to/modulename.so"); // Load the module
A more complicated method which builds the module directly into the php executable is described below.include("example.php");
Will be accessed in PHP like this :%module default int foo(int a); double bar(double, double b = 3.0); ...
dl("default.so"); $a = foo(2); $b = bar(3.5, -1.5); $c = bar(3.5); # Use default argument for 2nd parameter
is accessed as follow :%module example; ... double seki = 2; ... int example_func(void);
SWIG supports global variables of all C datatypes including pointers and complex objects.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
You can also explicitly create a NULL pointer as a string "NULL" or by passing a null or empty value.
This gets turned into the following collection of PHP functions :%module vector class Vector { public: double x,y,z; Vector(); ~Vector(); double magnitude(); };
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 belowVector_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);
%module example #define PI 3.14159 %constant int E = 2.71828
you can access from in your php script like this,
dl("libexample.so"); echo "PI = " . PI . "\n"; echo "E = " . E . "\n";
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,
accessed incorrectly in PHP,%module example #define EASY_TO_MISPELL 0
dl("libexample.so"); if(EASY_TO_MISPEL) { .... } else { .... }
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.
The second 'feature' is that although constants are case sensitive (by default), you cannot declare a constant twice with alternative cases. E.g.,
accessed from PHP,%module example #define TEST Hello #define Test World
dl("libexample.so"); echo TEST, Test;
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.
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. )
% swig -php4 -shadow tbc.i
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 .php 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 -> instead of the low level access or functions like before. .... ( more examples on the way ) ....
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.
%module example class Ko { static int threats; ... };
would be accessed in PHP as,
To set the static member variable, pass the value as the argument to the class function, e.g.dl("libexample.so"); echo "There has now been " . Ko::threats() . " threats\n";
Ko::threats(10); echo "There has now been " . Ko::threats() . " threats\n";
/* 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"
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 .)
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.
Before running the generated configure file, you may need to edit the Makefile.in. 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 Makefile.in will be complete, especially if you make use of -withlibs and -withincs
swig -php4 -phpfull -withlibs "xapian omquery" --withincs "om.h"
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
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.)
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.