mirror of https://github.com/swig/swig
[php] Generate PHP type declarations
We now automatically generate PHP type declarations for PHP >= 8.0. The generated code still compiles with PHP 7.x but without type declarations.
This commit is contained in:
parent
76d5a9ec27
commit
1f1349741f
|
@ -346,6 +346,79 @@ $c = bar(3.5); # Use default argument for 2nd parameter
|
|||
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
SWIG generates PHP type declarations for function parameters and return
|
||||
types for PHP 8 and later (we don't try to support PHP 7's more limited type
|
||||
declarations and the generated wrappers compiled for PHP 7 will not have any
|
||||
type declarations).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can control the generation of PHP type declarations using
|
||||
the "php:type" %feature. This has three settings:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li> <p>If unset or set to "0" then no type declarations are generated, e.g.: <tt>%feature("php:type", "0");</tt>
|
||||
</p></li>
|
||||
<li> <p>If set to "1" then type declarations are generated for both parameters and return types, e.g.: <tt>%feature("php:type", "1");</tt>
|
||||
</p></li>
|
||||
<li> <p>The default setting is "compat", which is the same as "1" except no
|
||||
return type declarations are generated for virtual methods for which
|
||||
directors are enabled. This provides better compatibility for PHP
|
||||
subclasses of wrapped virtual methods in existing SWIG-generated bindings, e.g.: <tt>%feature("php:type", "compat");</tt>
|
||||
</p></li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If you have an existing PHP interface and are upgrading to SWIG >= 4.1.0
|
||||
then the default "compat" setting should work well.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you're writing a new set of bindings and <b>only targetting PHP8 or newer</b>
|
||||
then enabling type declarations everywhere probably makes sense. It will
|
||||
only actually make a difference if you enable directors and are wrapping C++
|
||||
classes with virtual methods, but doing it anyway means you won't forget to if
|
||||
the code you are wrapping later evolves to have such classes and methods.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The type declaration information will make the generated source code and
|
||||
compiler extension module larger, so you might want to turn off type
|
||||
declarations if keeping these small is important to you. If you find you
|
||||
need to turn off type declarations to fix a problem, please let us know
|
||||
via our github issue tracker.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that being a SWIG feature this can be specified globally (like above) or
|
||||
per class, per method, etc. See the <a
|
||||
href="Customization.html#Customization_features">%feature directives</a>
|
||||
section for full details of how to control at a fine-grained level.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The PHP type information is specified via a "phptype" attribute on "in" and
|
||||
"out" typemaps, and these have been added for all the typemaps we supply for
|
||||
PHP. We don't currently support this for "argout" templates, but probably
|
||||
will in a future version.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you have written custom SWIG typemaps for PHP and want to add PHP type
|
||||
declarations, then the syntax is very like how you'd specify the type in
|
||||
PHP code, e.g. <tt>%typemap(in, phptype="int|string|Foo")</tt> means the
|
||||
typemap accepts a PHP int or string or an object of class Foo,
|
||||
<tt>%typemap(in, phptype="?int")</tt> means a PHP int or NULL, etc.
|
||||
As well as the standard PHP type declaration types, SWIG also understands the
|
||||
special type "SWIGTYPE" as an entry in phptype, which means the PHP type
|
||||
corresponding to the type that this typemap matched on - for a object this
|
||||
will give you the PHP class for the object, and for a pointer to a non-class
|
||||
type it will give you the name of the PHP class SWIG created for that
|
||||
pointer type.
|
||||
</p>
|
||||
|
||||
<!-- 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
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
struct Geometry {
|
||||
enum GeomType{
|
||||
POINT,
|
||||
CIRCLE
|
||||
CIRCLE,
|
||||
SHAPELESS
|
||||
};
|
||||
|
||||
virtual ~Geometry() {}
|
||||
|
|
|
@ -20,11 +20,14 @@ $tr=copy_intp(4);
|
|||
check::equal(4,inctr($tr),"4==incr($tr)");
|
||||
check::equal(5,intp_value($tr),"5==$tr");
|
||||
|
||||
# Check the voidhandle call, first with null
|
||||
# Check the voidhandle call, first with NULL and then with the SWIG\p_void we
|
||||
# get from the first call.
|
||||
$handle=NULL;
|
||||
voidhandle($handle);
|
||||
check::equal(get_class($handle),"SWIG\\_p_void",'$handle is not _p_void');
|
||||
$handledata=handle($handle);
|
||||
check::equal($handledata,"Here it is","\$handledata != \"Here it is\"");
|
||||
for ($i=0; $i != 1; $i++) {
|
||||
voidhandle($handle);
|
||||
check::equal(get_class($handle),"SWIG\\_p_void",'$handle is not _p_void');
|
||||
$handledata=handle($handle);
|
||||
check::equal($handledata,"Here it is","\$handledata != \"Here it is\"");
|
||||
}
|
||||
|
||||
check::done();
|
||||
|
|
|
@ -17,4 +17,7 @@ $point = Geometry::create(Geometry::POINT);
|
|||
$w = $point->width();
|
||||
check::equal($w, 1.0, "w failed");
|
||||
|
||||
$point = Geometry::create(Geometry::SHAPELESS);
|
||||
check::equal($point, NULL, "NULL failed");
|
||||
|
||||
check::done();
|
||||
|
|
|
@ -100,7 +100,7 @@ if (!dcast) {
|
|||
}%enddef
|
||||
|
||||
%define %factory(Method,Types...)
|
||||
%typemap(out) Method {
|
||||
%typemap(out, phptype="?SWIGTYPE") Method {
|
||||
int dcast = 0;
|
||||
%formacro(%_factory_dispatch, Types)
|
||||
if (!dcast) {
|
||||
|
|
135
Lib/php/php.swg
135
Lib/php/php.swg
|
@ -4,6 +4,11 @@
|
|||
* PHP configuration file
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
// Default to generating PHP type declarations (for PHP >= 8) except for
|
||||
// cases which are liable to cause compatibility issues with existing
|
||||
// bindings.
|
||||
%feature("php:type", "compat");
|
||||
|
||||
%runtime "swigrun.swg" // Common C API type-checking code
|
||||
%runtime "swigerrors.swg" // SWIG errors
|
||||
%runtime "phprun.swg" // PHP runtime functions
|
||||
|
@ -34,56 +39,56 @@
|
|||
|
||||
%include <utils.i>
|
||||
|
||||
%pass_by_val(bool,CONVERT_BOOL_IN);
|
||||
%pass_by_val(bool, "bool", CONVERT_BOOL_IN);
|
||||
|
||||
%pass_by_val(size_t, CONVERT_INT_IN);
|
||||
%pass_by_val(size_t, "int", CONVERT_INT_IN);
|
||||
|
||||
%pass_by_val(enum SWIGTYPE, CONVERT_INT_IN);
|
||||
%pass_by_val(enum SWIGTYPE, "int", CONVERT_INT_IN);
|
||||
|
||||
%pass_by_val(signed int, CONVERT_INT_IN);
|
||||
%pass_by_val(int,CONVERT_INT_IN);
|
||||
%pass_by_val(unsigned int,CONVERT_INT_IN);
|
||||
%pass_by_val(signed int, "int", CONVERT_INT_IN);
|
||||
%pass_by_val(int,"int", CONVERT_INT_IN);
|
||||
%pass_by_val(unsigned int,"int", CONVERT_INT_IN);
|
||||
|
||||
%pass_by_val(signed short, CONVERT_INT_IN);
|
||||
%pass_by_val(short,CONVERT_INT_IN);
|
||||
%pass_by_val(unsigned short, CONVERT_INT_IN);
|
||||
%pass_by_val(signed short, "int", CONVERT_INT_IN);
|
||||
%pass_by_val(short,"int", CONVERT_INT_IN);
|
||||
%pass_by_val(unsigned short, "int", CONVERT_INT_IN);
|
||||
|
||||
%pass_by_val(signed long, CONVERT_INT_IN);
|
||||
%pass_by_val(long, CONVERT_INT_IN);
|
||||
%pass_by_val(unsigned long, CONVERT_INT_IN);
|
||||
%pass_by_val(signed long, "int", CONVERT_INT_IN);
|
||||
%pass_by_val(long, "int", CONVERT_INT_IN);
|
||||
%pass_by_val(unsigned long, "int", CONVERT_INT_IN);
|
||||
|
||||
%pass_by_val(signed long long, CONVERT_LONG_LONG_IN);
|
||||
%pass_by_val(long long, CONVERT_LONG_LONG_IN);
|
||||
%pass_by_val(unsigned long long, CONVERT_UNSIGNED_LONG_LONG_IN);
|
||||
%pass_by_val(signed long long, "int|string", CONVERT_LONG_LONG_IN);
|
||||
%pass_by_val(long long, "int|string", CONVERT_LONG_LONG_IN);
|
||||
%pass_by_val(unsigned long long, "int|string", CONVERT_UNSIGNED_LONG_LONG_IN);
|
||||
|
||||
%pass_by_val(signed char, CONVERT_INT_IN);
|
||||
%pass_by_val(char, CONVERT_CHAR_IN);
|
||||
%pass_by_val(unsigned char, CONVERT_INT_IN);
|
||||
%pass_by_val(signed char, "int", CONVERT_INT_IN);
|
||||
%pass_by_val(char, "string", CONVERT_CHAR_IN);
|
||||
%pass_by_val(unsigned char, "int", CONVERT_INT_IN);
|
||||
|
||||
%pass_by_val(float, CONVERT_FLOAT_IN);
|
||||
%pass_by_val(float, "float", CONVERT_FLOAT_IN);
|
||||
|
||||
%pass_by_val(double, CONVERT_FLOAT_IN);
|
||||
%pass_by_val(double, "float", CONVERT_FLOAT_IN);
|
||||
|
||||
%pass_by_val(char *, CONVERT_STRING_IN);
|
||||
%pass_by_val(char *, "string", CONVERT_STRING_IN);
|
||||
%typemap(in) char *& = const char *&;
|
||||
%typemap(directorout) char *& = const char *&;
|
||||
|
||||
// char array can be in/out, though the passed string may not be big enough...
|
||||
// so we have to size it
|
||||
%typemap(in) char[ANY]
|
||||
%typemap(in, phptype="string") char[ANY]
|
||||
%{
|
||||
convert_to_string(&$input);
|
||||
$1 = ($1_ltype) Z_STRVAL($input);
|
||||
%}
|
||||
|
||||
%typemap(in) (char *STRING, int LENGTH), (char *STRING, size_t LENGTH) %{
|
||||
%typemap(in, phptype="string") (char *STRING, int LENGTH), (char *STRING, size_t LENGTH) %{
|
||||
convert_to_string(&$input);
|
||||
$1 = ($1_ltype) Z_STRVAL($input);
|
||||
$2 = ($2_ltype) Z_STRLEN($input);
|
||||
%}
|
||||
|
||||
/* Object passed by value. Convert to a pointer */
|
||||
%typemap(in) SWIGTYPE ($&1_ltype tmp)
|
||||
%typemap(in, phptype="SWIGTYPE") SWIGTYPE ($&1_ltype tmp)
|
||||
%{
|
||||
if (SWIG_ConvertPtr(&$input, (void **) &tmp, $&1_descriptor, 0) < 0 || tmp == NULL) {
|
||||
zend_type_error("Expected $&1_descriptor for argument $argnum of $symname");
|
||||
|
@ -101,7 +106,7 @@
|
|||
$result = *tmp;
|
||||
%}
|
||||
|
||||
%typemap(in) SWIGTYPE *,
|
||||
%typemap(in, phptype="?SWIGTYPE") SWIGTYPE *,
|
||||
SWIGTYPE []
|
||||
%{
|
||||
if (SWIG_ConvertPtr(&$input, (void **) &$1, $1_descriptor, 0) < 0) {
|
||||
|
@ -120,7 +125,7 @@
|
|||
swig_acquire_ownership_obj((void*)$result, own);
|
||||
%}
|
||||
|
||||
%typemap(in) SWIGTYPE &,
|
||||
%typemap(in, phptype="SWIGTYPE") SWIGTYPE &,
|
||||
SWIGTYPE &&
|
||||
%{
|
||||
if (SWIG_ConvertPtr(&$input, (void **) &$1, $1_descriptor, 0) < 0 || $1 == NULL) {
|
||||
|
@ -139,7 +144,7 @@
|
|||
$result = tmp;
|
||||
%}
|
||||
|
||||
%typemap(in) SWIGTYPE *const& ($*ltype temp)
|
||||
%typemap(in, phptype="?SWIGTYPE") SWIGTYPE *const& ($*ltype temp)
|
||||
%{
|
||||
if (SWIG_ConvertPtr(&$input, (void **) &temp, $*1_descriptor, 0) < 0) {
|
||||
zend_type_error("Expected $*1_descriptor for argument $argnum of $symname");
|
||||
|
@ -148,7 +153,7 @@
|
|||
$1 = ($1_ltype)&temp;
|
||||
%}
|
||||
|
||||
%typemap(in) SWIGTYPE *DISOWN
|
||||
%typemap(in, phptype="?SWIGTYPE") SWIGTYPE *DISOWN
|
||||
%{
|
||||
if (SWIG_ConvertPtr(&$input, (void **) &$1, $1_descriptor, SWIG_POINTER_DISOWN) < 0) {
|
||||
zend_type_error("Expected $1_descriptor for argument $argnum of $symname");
|
||||
|
@ -161,7 +166,7 @@
|
|||
SWIGTYPE &,
|
||||
SWIGTYPE &&;
|
||||
|
||||
%typemap(in) void *
|
||||
%typemap(in, phptype="?SWIGTYPE") void *
|
||||
%{
|
||||
if (SWIG_ConvertPtr(&$input, (void **) &$1, 0, 0) < 0) {
|
||||
/* Allow NULL from php for void* */
|
||||
|
@ -176,7 +181,7 @@
|
|||
|
||||
/* Special case when void* is passed by reference so it can be made to point
|
||||
to opaque api structs */
|
||||
%typemap(in, byref=1) void ** ($*1_ltype ptr, int force),
|
||||
%typemap(in, phptype="?SWIG\\_p_void", byref=1) void ** ($*1_ltype ptr, int force),
|
||||
void *& ($*1_ltype ptr, int force)
|
||||
{
|
||||
/* If they pass NULL by reference, make it into a void*
|
||||
|
@ -211,7 +216,8 @@
|
|||
|
||||
/* Typemap for output values */
|
||||
|
||||
%typemap(out) int,
|
||||
%typemap(out, phptype="int")
|
||||
int,
|
||||
unsigned int,
|
||||
short,
|
||||
unsigned short,
|
||||
|
@ -224,12 +230,12 @@
|
|||
RETVAL_LONG($1);
|
||||
%}
|
||||
|
||||
%typemap(out) enum SWIGTYPE
|
||||
%typemap(out, phptype="int") enum SWIGTYPE
|
||||
%{
|
||||
RETVAL_LONG((long)$1);
|
||||
%}
|
||||
|
||||
%typemap(out) long long
|
||||
%typemap(out, phptype="int|string") long long
|
||||
%{
|
||||
if ((long long)LONG_MIN <= $1 && $1 <= (long long)LONG_MAX) {
|
||||
RETVAL_LONG((long)($1));
|
||||
|
@ -239,7 +245,7 @@
|
|||
RETVAL_STRING(temp);
|
||||
}
|
||||
%}
|
||||
%typemap(out) unsigned long long
|
||||
%typemap(out, phptype="int|string") unsigned long long
|
||||
%{
|
||||
if ($1 <= (unsigned long long)LONG_MAX) {
|
||||
RETVAL_LONG((long)($1));
|
||||
|
@ -250,7 +256,8 @@
|
|||
}
|
||||
%}
|
||||
|
||||
%typemap(out) const int &,
|
||||
%typemap(out, phptype="int")
|
||||
const int &,
|
||||
const unsigned int &,
|
||||
const short &,
|
||||
const unsigned short &,
|
||||
|
@ -264,17 +271,17 @@
|
|||
RETVAL_LONG(*$1);
|
||||
%}
|
||||
|
||||
%typemap(out) const enum SWIGTYPE &
|
||||
%typemap(out, phptype="int") const enum SWIGTYPE &
|
||||
%{
|
||||
RETVAL_LONG((long)*$1);
|
||||
%}
|
||||
|
||||
%typemap(out) const enum SWIGTYPE &&
|
||||
%typemap(out, phptype="int") const enum SWIGTYPE &&
|
||||
%{
|
||||
RETVAL_LONG((long)*$1);
|
||||
%}
|
||||
|
||||
%typemap(out) const long long &
|
||||
%typemap(out, phptype="int|string") const long long &
|
||||
%{
|
||||
if ((long long)LONG_MIN <= *$1 && *$1 <= (long long)LONG_MAX) {
|
||||
RETVAL_LONG((long)(*$1));
|
||||
|
@ -284,7 +291,7 @@
|
|||
RETVAL_STRING(temp);
|
||||
}
|
||||
%}
|
||||
%typemap(out) const unsigned long long &
|
||||
%typemap(out, phptype="int|string") const unsigned long long &
|
||||
%{
|
||||
if (*$1 <= (unsigned long long)LONG_MAX) {
|
||||
RETVAL_LONG((long)(*$1));
|
||||
|
@ -323,12 +330,12 @@
|
|||
}
|
||||
%}
|
||||
|
||||
%typemap(out) bool
|
||||
%typemap(out, phptype="bool") bool
|
||||
%{
|
||||
RETVAL_BOOL(($1) ? 1 : 0);
|
||||
%}
|
||||
|
||||
%typemap(out) const bool &
|
||||
%typemap(out, phptype="bool") const bool &
|
||||
%{
|
||||
RETVAL_BOOL((*$1) ? 1 : 0);
|
||||
%}
|
||||
|
@ -338,13 +345,13 @@
|
|||
ZVAL_BOOL($input, ($1) ? 1 : 0);
|
||||
%}
|
||||
|
||||
%typemap(out) float,
|
||||
%typemap(out, phptype="float") float,
|
||||
double
|
||||
%{
|
||||
RETVAL_DOUBLE($1);
|
||||
%}
|
||||
|
||||
%typemap(out) const float &,
|
||||
%typemap(out, phptype="float") const float &,
|
||||
const double &
|
||||
%{
|
||||
RETVAL_DOUBLE(*$1);
|
||||
|
@ -356,18 +363,22 @@
|
|||
ZVAL_DOUBLE($input, $1);
|
||||
%}
|
||||
|
||||
%typemap(out) char
|
||||
%typemap(out, phptype="string") char
|
||||
%{
|
||||
RETVAL_STRINGL(&$1, 1);
|
||||
%}
|
||||
|
||||
%typemap(out) const char &
|
||||
%typemap(out, phptype="string") const char &
|
||||
%{
|
||||
RETVAL_STRINGL(&*$1, 1);
|
||||
%}
|
||||
|
||||
%typemap(out) char *,
|
||||
char []
|
||||
%typemap(out, phptype="string") char []
|
||||
%{
|
||||
RETVAL_STRING((const char *)$1);
|
||||
%}
|
||||
|
||||
%typemap(out, phptype="?string") char *
|
||||
%{
|
||||
if (!$1) {
|
||||
RETVAL_NULL();
|
||||
|
@ -376,7 +387,7 @@
|
|||
}
|
||||
%}
|
||||
|
||||
%typemap(out) char *&
|
||||
%typemap(out, phptype="?string") char *&
|
||||
%{
|
||||
if (!*$1) {
|
||||
RETVAL_NULL();
|
||||
|
@ -385,7 +396,12 @@
|
|||
}
|
||||
%}
|
||||
|
||||
%typemap(out) SWIGTYPE *,
|
||||
%typemap(out, phptype="?SWIGTYPE") SWIGTYPE *
|
||||
%{
|
||||
SWIG_SetPointerZval($result, (void *)$1, $1_descriptor, $owner);
|
||||
%}
|
||||
|
||||
%typemap(out, phptype="SWIGTYPE")
|
||||
SWIGTYPE [],
|
||||
SWIGTYPE &,
|
||||
SWIGTYPE &&
|
||||
|
@ -393,7 +409,7 @@
|
|||
SWIG_SetPointerZval($result, (void *)$1, $1_descriptor, $owner);
|
||||
%}
|
||||
|
||||
%typemap(out) SWIGTYPE *const&
|
||||
%typemap(out, phptype="?SWIGTYPE") SWIGTYPE *const&
|
||||
%{
|
||||
SWIG_SetPointerZval($result, (void *)*$1, $*1_descriptor, $owner);
|
||||
%}
|
||||
|
@ -406,27 +422,32 @@
|
|||
SWIG_SetPointerZval($input, (void *)&$1, $1_descriptor, $owner);
|
||||
%}
|
||||
|
||||
%typemap(out) SWIGTYPE (CLASS::*)
|
||||
%typemap(out, phptype="SWIGTYPE") SWIGTYPE (CLASS::*)
|
||||
{
|
||||
void * p = emalloc(sizeof($1));
|
||||
memcpy(p, &$1, sizeof($1));
|
||||
SWIG_SetPointerZval($result, (void *)p, $&1_descriptor, 1);
|
||||
}
|
||||
|
||||
%typemap(in) SWIGTYPE (CLASS::*)
|
||||
%typemap(in, phptype="SWIGTYPE") SWIGTYPE (CLASS::*)
|
||||
{
|
||||
void * p = SWIG_Z_FETCH_OBJ_P(&$input)->ptr;
|
||||
memcpy(&$1, p, sizeof($1));
|
||||
}
|
||||
|
||||
%typemap(out) SWIGTYPE *DYNAMIC,
|
||||
SWIGTYPE &DYNAMIC
|
||||
%typemap(out, phptype="?SWIGTYPE") SWIGTYPE *DYNAMIC
|
||||
{
|
||||
swig_type_info *ty = SWIG_TypeDynamicCast($1_descriptor, (void **) &$1);
|
||||
SWIG_SetPointerZval($result, (void *)$1, ty, $owner);
|
||||
}
|
||||
|
||||
%typemap(out) SWIGTYPE
|
||||
%typemap(out, phptype="SWIGTYPE") SWIGTYPE &DYNAMIC
|
||||
{
|
||||
swig_type_info *ty = SWIG_TypeDynamicCast($1_descriptor, (void **) &$1);
|
||||
SWIG_SetPointerZval($result, (void *)$1, ty, $owner);
|
||||
}
|
||||
|
||||
%typemap(out, phptype="SWIGTYPE") SWIGTYPE
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
$&1_ltype resultobj = new $1_ltype((const $1_ltype &) $1);
|
||||
|
@ -442,9 +463,9 @@
|
|||
SWIG_SetPointerZval($input, SWIG_as_voidptr(new $1_ltype((const $1_ltype &)$1)), $&1_descriptor, 1);
|
||||
%}
|
||||
|
||||
%typemap(out) void "";
|
||||
%typemap(out, phptype="void") void "";
|
||||
|
||||
%typemap(out) char [ANY]
|
||||
%typemap(out, phptype="string") char [ANY]
|
||||
{
|
||||
size_t len = 0;
|
||||
while (len < $1_dim0 && $1[len]) ++len;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%define %pass_by_ref( TYPE, CONVERT_IN, CONVERT_OUT )
|
||||
%typemap(in, byref=1) TYPE *REF ($*1_ltype tmp),
|
||||
%define %pass_by_ref( TYPE, PHP_TYPE, CONVERT_IN, CONVERT_OUT )
|
||||
%typemap(in,byref=1,phptype=PHP_TYPE) TYPE *REF ($*1_ltype tmp),
|
||||
TYPE &REF ($*1_ltype tmp)
|
||||
%{
|
||||
if (Z_ISREF($input)) {
|
||||
|
@ -18,25 +18,25 @@
|
|||
%}
|
||||
%enddef
|
||||
|
||||
%pass_by_ref( size_t, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( size_t, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
|
||||
%pass_by_ref( signed int, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( int, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( unsigned int, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( signed int, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( int, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( unsigned int, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
|
||||
%pass_by_ref( signed short, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( short, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( unsigned short, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( signed short, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( short, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( unsigned short, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
|
||||
%pass_by_ref( signed long, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( long, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( unsigned long, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( signed long, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( long, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( unsigned long, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
|
||||
%pass_by_ref( signed char, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( char, CONVERT_CHAR_IN, ZVAL_STRING );
|
||||
%pass_by_ref( unsigned char, CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( signed char, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
%pass_by_ref( char, "string", CONVERT_CHAR_IN, ZVAL_STRING );
|
||||
%pass_by_ref( unsigned char, "int", CONVERT_INT_IN, ZVAL_LONG );
|
||||
|
||||
%pass_by_ref( float, CONVERT_FLOAT_IN, ZVAL_DOUBLE );
|
||||
%pass_by_ref( double, CONVERT_FLOAT_IN, ZVAL_DOUBLE );
|
||||
%pass_by_ref( float, "float", CONVERT_FLOAT_IN, ZVAL_DOUBLE );
|
||||
%pass_by_ref( double, "float", CONVERT_FLOAT_IN, ZVAL_DOUBLE );
|
||||
|
||||
%pass_by_ref( char *, CONVERT_CHAR_IN, ZVAL_STRING );
|
||||
%pass_by_ref( char *, "string", CONVERT_CHAR_IN, ZVAL_STRING );
|
||||
|
|
|
@ -20,6 +20,27 @@ extern "C" {
|
|||
#include "zend_exceptions.h"
|
||||
#include "zend_inheritance.h"
|
||||
|
||||
#if PHP_MAJOR_VERSION == 7
|
||||
/* These macros were new in PHP 8.0. For PHP 7.x we define them to give the
|
||||
* same result except without any type declarations. PHP 7.x supports type
|
||||
* declarations, but not for the return type, and alternate types aren't
|
||||
* supported, so we don't try to support these.
|
||||
*/
|
||||
# define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(name, byref, num_req, classes, types) \
|
||||
ZEND_BEGIN_ARG_INFO_EX(name, 0, byref, num_req)
|
||||
# define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(name, byref, num_req, types) \
|
||||
ZEND_BEGIN_ARG_INFO_EX(name, 0, byref, num_req)
|
||||
|
||||
/* NB We can just ignore `default` here we currently always pass NULL for it
|
||||
* (this mechnism for specifying default parameter values was new in PHP 8.0
|
||||
* so it's not useful while we still want to support PHP7 too).
|
||||
*/
|
||||
# define ZEND_ARG_OBJ_TYPE_MASK(byref, name, classes, types, default) \
|
||||
ZEND_ARG_INFO(byref, name)
|
||||
# define ZEND_ARG_TYPE_MASK(byref, name, types, default) \
|
||||
ZEND_ARG_INFO(byref, name)
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> /* for abort(), used in generated code. */
|
||||
|
||||
#define SWIG_BOOL_CONSTANT(N, V) REGISTER_BOOL_CONSTANT(#N, V, CONST_CS | CONST_PERSISTENT)
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace std {
|
|||
$1 = (Z_TYPE($input) == IS_STRING) ? 1 : 0;
|
||||
%}
|
||||
|
||||
%typemap(in) string %{
|
||||
%typemap(in, phptype="string") string %{
|
||||
convert_to_string(&$input);
|
||||
$1.assign(Z_STRVAL($input), Z_STRLEN($input));
|
||||
%}
|
||||
|
@ -37,7 +37,7 @@ namespace std {
|
|||
$result.assign(Z_STRVAL_P($input), Z_STRLEN_P($input));
|
||||
%}
|
||||
|
||||
%typemap(out) string %{
|
||||
%typemap(out, phptype="string") string %{
|
||||
ZVAL_STRINGL($result, $1.data(), $1.size());
|
||||
%}
|
||||
|
||||
|
@ -45,7 +45,7 @@ namespace std {
|
|||
ZVAL_STRINGL($input, $1.data(), $1.size());
|
||||
%}
|
||||
|
||||
%typemap(out) const string & %{
|
||||
%typemap(out, phptype="string") const string & %{
|
||||
ZVAL_STRINGL($result, $1->data(), $1->size());
|
||||
%}
|
||||
|
||||
|
@ -54,7 +54,7 @@ namespace std {
|
|||
return;
|
||||
%}
|
||||
|
||||
%typemap(in) const string & ($*1_ltype temp) %{
|
||||
%typemap(in, phptype="string") const string & ($*1_ltype temp) %{
|
||||
convert_to_string(&$input);
|
||||
temp.assign(Z_STRVAL($input), Z_STRLEN($input));
|
||||
$1 = &temp;
|
||||
|
@ -62,7 +62,7 @@ namespace std {
|
|||
|
||||
/* These next two handle a function which takes a non-const reference to
|
||||
* a std::string and modifies the string. */
|
||||
%typemap(in,byref=1) string & ($*1_ltype temp) %{
|
||||
%typemap(in,byref=1, phptype="string") string & ($*1_ltype temp) %{
|
||||
{
|
||||
zval * p = Z_ISREF($input) ? Z_REFVAL($input) : &$input;
|
||||
convert_to_string(p);
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%define BOOL_TYPEMAP(TYPE)
|
||||
%typemap(in) TYPE *INPUT(TYPE temp), TYPE &INPUT(TYPE temp)
|
||||
%typemap(in, phptype="bool") TYPE *INPUT(TYPE temp), TYPE &INPUT(TYPE temp)
|
||||
%{
|
||||
convert_to_boolean(&$input);
|
||||
temp = (Z_TYPE($input) == IS_TRUE);
|
||||
|
@ -39,7 +39,7 @@
|
|||
ZVAL_BOOL(&o, temp$argnum);
|
||||
t_output_helper($result, &o);
|
||||
}
|
||||
%typemap(in) TYPE *REFERENCE (TYPE lvalue), TYPE &REFERENCE (TYPE lvalue)
|
||||
%typemap(in, phptype="float") TYPE *REFERENCE (TYPE lvalue), TYPE &REFERENCE (TYPE lvalue)
|
||||
%{
|
||||
convert_to_boolean($input);
|
||||
lvalue = (Z_TYPE_P($input) == IS_TRUE);
|
||||
|
@ -52,7 +52,7 @@
|
|||
%enddef
|
||||
|
||||
%define DOUBLE_TYPEMAP(TYPE)
|
||||
%typemap(in) TYPE *INPUT(TYPE temp), TYPE &INPUT(TYPE temp)
|
||||
%typemap(in, phptype="float") TYPE *INPUT(TYPE temp), TYPE &INPUT(TYPE temp)
|
||||
%{
|
||||
temp = (TYPE) zval_get_double(&$input);
|
||||
$1 = &temp;
|
||||
|
@ -65,7 +65,7 @@
|
|||
ZVAL_DOUBLE(&o, temp$argnum);
|
||||
t_output_helper($result, &o);
|
||||
}
|
||||
%typemap(in) TYPE *REFERENCE (TYPE dvalue), TYPE &REFERENCE (TYPE dvalue)
|
||||
%typemap(in, phptype="float") TYPE *REFERENCE (TYPE dvalue), TYPE &REFERENCE (TYPE dvalue)
|
||||
%{
|
||||
dvalue = (TYPE) zval_get_double(&$input);
|
||||
$1 = &dvalue;
|
||||
|
@ -77,7 +77,7 @@
|
|||
%enddef
|
||||
|
||||
%define INT_TYPEMAP(TYPE)
|
||||
%typemap(in) TYPE *INPUT(TYPE temp), TYPE &INPUT(TYPE temp)
|
||||
%typemap(in, phptype="int") TYPE *INPUT(TYPE temp), TYPE &INPUT(TYPE temp)
|
||||
%{
|
||||
temp = (TYPE) zval_get_long(&$input);
|
||||
$1 = &temp;
|
||||
|
@ -90,7 +90,7 @@
|
|||
ZVAL_LONG(&o, temp$argnum);
|
||||
t_output_helper($result, &o);
|
||||
}
|
||||
%typemap(in) TYPE *REFERENCE (TYPE lvalue), TYPE &REFERENCE (TYPE lvalue)
|
||||
%typemap(in, phptype="int") TYPE *REFERENCE (TYPE lvalue), TYPE &REFERENCE (TYPE lvalue)
|
||||
%{
|
||||
lvalue = (TYPE) zval_get_long(&$input);
|
||||
$1 = &lvalue;
|
||||
|
@ -128,7 +128,7 @@ INT_TYPEMAP(long long);
|
|||
}
|
||||
t_output_helper($result, &o);
|
||||
}
|
||||
%typemap(in) TYPE *REFERENCE (long long lvalue)
|
||||
%typemap(in, phptype="int|string") TYPE *REFERENCE (long long lvalue)
|
||||
%{
|
||||
CONVERT_LONG_LONG_IN(lvalue, long long, $input)
|
||||
$1 = &lvalue;
|
||||
|
@ -167,7 +167,7 @@ INT_TYPEMAP(unsigned long long);
|
|||
}
|
||||
t_output_helper($result, &o);
|
||||
}
|
||||
%typemap(in) TYPE *REFERENCE (unsigned long long lvalue)
|
||||
%typemap(in, phptype="int|string") TYPE *REFERENCE (unsigned long long lvalue)
|
||||
%{
|
||||
CONVERT_UNSIGNED_LONG_LONG_IN(lvalue, unsigned long long, $input)
|
||||
$1 = &lvalue;
|
||||
|
@ -253,7 +253,7 @@ INT_TYPEMAP(unsigned long long);
|
|||
%typemap(argout) unsigned long long &INOUT = unsigned long long *OUTPUT;
|
||||
%typemap(argout) signed char &INOUT = signed char *OUTPUT;
|
||||
|
||||
%typemap(in) char INPUT[ANY] ( char temp[$1_dim0] )
|
||||
%typemap(in, phptype="string") char INPUT[ANY] ( char temp[$1_dim0] )
|
||||
%{
|
||||
convert_to_string(&$input);
|
||||
strncpy(temp, Z_STRVAL($input), $1_dim0);
|
||||
|
@ -268,7 +268,7 @@ INT_TYPEMAP(unsigned long long);
|
|||
t_output_helper($result, &o);
|
||||
}
|
||||
|
||||
%typemap(in,numinputs=0) void **OUTPUT (int force),
|
||||
%typemap(in,numinputs=0,phptype="?SWIGTYPE") void **OUTPUT (int force),
|
||||
void *&OUTPUT (int force)
|
||||
%{
|
||||
/* If they pass NULL by reference, make it into a void*
|
||||
|
|
|
@ -63,12 +63,12 @@
|
|||
}
|
||||
%enddef
|
||||
|
||||
%define %pass_by_val( TYPE, CONVERT_IN )
|
||||
%typemap(in) TYPE
|
||||
%define %pass_by_val( TYPE, PHP_TYPE, CONVERT_IN )
|
||||
%typemap(in, phptype=PHP_TYPE) TYPE
|
||||
%{
|
||||
CONVERT_IN($1,$1_ltype,$input);
|
||||
%}
|
||||
%typemap(in) const TYPE & ($*1_ltype temp)
|
||||
%typemap(in, phptype=PHP_TYPE) const TYPE & ($*1_ltype temp)
|
||||
%{
|
||||
CONVERT_IN(temp,$*1_ltype,$input);
|
||||
$1 = &temp;
|
||||
|
|
|
@ -176,7 +176,95 @@ static void SwigPHP_emit_pointer_type_registrations() {
|
|||
}
|
||||
}
|
||||
|
||||
// Class encapsulating the machinery to add PHP type declarations.
|
||||
class PHPTypes {
|
||||
Hash *phptypes;
|
||||
|
||||
// List with an entry for each parameter and one for the return type.
|
||||
//
|
||||
// We assemble the types in here before emitting them so for an overloaded
|
||||
// function we combine the type declarations from each overloaded form.
|
||||
List *merged_types;
|
||||
|
||||
// List with an entry for each parameter which is passed "byref" in any
|
||||
// overloaded form. We use this to pass such parameters by reference in
|
||||
// the dispatch function. If NULL, no parameters are passed by reference.
|
||||
List *byref;
|
||||
|
||||
public:
|
||||
PHPTypes() : phptypes(NewHash()), merged_types(NULL), byref(NULL) {
|
||||
Setattr(phptypes, "array", "MAY_BE_ARRAY");
|
||||
Setattr(phptypes, "bool", "MAY_BE_BOOL");
|
||||
Setattr(phptypes, "callable", "MAY_BE_CALLABLE");
|
||||
Setattr(phptypes, "float", "MAY_BE_DOUBLE");
|
||||
Setattr(phptypes, "int", "MAY_BE_LONG");
|
||||
Setattr(phptypes, "iterable", "MAY_BE_ITERABLE");
|
||||
Setattr(phptypes, "mixed", "MAY_BE_MIXED");
|
||||
Setattr(phptypes, "null", "MAY_BE_NULL");
|
||||
Setattr(phptypes, "object", "MAY_BE_OBJECT");
|
||||
Setattr(phptypes, "resource", "MAY_BE_RESOURCE");
|
||||
Setattr(phptypes, "string", "MAY_BE_STRING");
|
||||
Setattr(phptypes, "void", "MAY_BE_VOID");
|
||||
}
|
||||
|
||||
void reset() {
|
||||
Delete(merged_types);
|
||||
merged_types = NewList();
|
||||
Delete(byref);
|
||||
byref = NULL;
|
||||
}
|
||||
|
||||
// key is 0 for return type, or >= 1 for parameters numbered from 1
|
||||
void process_phptype(Node *n, int key, const String_or_char *attribute_name);
|
||||
|
||||
String *get_phptype(int key, String *classtypes) {
|
||||
Clear(classtypes);
|
||||
DOH *types = Getitem(merged_types, key);
|
||||
String *result = NewStringEmpty();
|
||||
if (types != None) {
|
||||
SortList(types, NULL);
|
||||
String *prev = NULL;
|
||||
for (Iterator i = First(types); i.item; i = Next(i)) {
|
||||
if (prev && Equal(prev, i.item)) {
|
||||
// Skip duplicates when merging.
|
||||
continue;
|
||||
}
|
||||
String *c = Getattr(phptypes, i.item);
|
||||
if (c) {
|
||||
if (Len(result) > 0) Append(result, "|");
|
||||
Append(result, c);
|
||||
} else {
|
||||
if (Len(classtypes) > 0) Append(classtypes, "|");
|
||||
Append(classtypes, i.item);
|
||||
}
|
||||
prev = i.item;
|
||||
}
|
||||
}
|
||||
// Make the mask 0 if there are only class names specified.
|
||||
if (Len(result) == 0) {
|
||||
Append(result, "0");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void set_byref(int key) {
|
||||
if (!byref) {
|
||||
byref = NewList();
|
||||
}
|
||||
while (Len(byref) <= key) {
|
||||
Append(byref, None);
|
||||
}
|
||||
Setitem(byref, key, ""); // Just needs to be something != None.
|
||||
}
|
||||
|
||||
int get_byref(int key) const {
|
||||
return byref && key < Len(byref) && Getitem(byref, key) != None;
|
||||
}
|
||||
};
|
||||
|
||||
class PHP : public Language {
|
||||
PHPTypes phptypes;
|
||||
|
||||
public:
|
||||
PHP() {
|
||||
director_language = 1;
|
||||
|
@ -572,124 +660,165 @@ public:
|
|||
}
|
||||
|
||||
/* Just need to append function names to function table to register with PHP. */
|
||||
void create_command(String *cname, String *fname, Node *n, bool overload, String *modes = NULL) {
|
||||
void create_command(String *cname, String *fname, Node *n, bool dispatch, String *modes = NULL) {
|
||||
// This is for the single main zend_function_entry record
|
||||
bool has_this = false;
|
||||
ParmList *l = Getattr(n, "parms");
|
||||
if (cname && Cmp(Getattr(n, "storage"), "friend") != 0) {
|
||||
Printf(f_h, "PHP_METHOD(%s%s,%s);\n", prefix, cname, fname);
|
||||
has_this = (wrapperType != staticmemberfn) &&
|
||||
(wrapperType != staticmembervar) &&
|
||||
(Cmp(fname, "__construct") != 0);
|
||||
if (wrapperType != staticmemberfn &&
|
||||
wrapperType != staticmembervar &&
|
||||
!Equal(fname, "__construct")) {
|
||||
// Skip the first entry in the parameter list which is the this pointer.
|
||||
l = Getattr(l, "tmap:in:next");
|
||||
// FIXME: does this throw the phptype key value off?
|
||||
}
|
||||
} else {
|
||||
if (overload) {
|
||||
if (dispatch) {
|
||||
Printf(f_h, "ZEND_NAMED_FUNCTION(%s);\n", fname);
|
||||
} else {
|
||||
Printf(f_h, "PHP_FUNCTION(%s);\n", fname);
|
||||
}
|
||||
}
|
||||
|
||||
int num_required = emit_num_required(l);
|
||||
|
||||
// We want to only emit each different arginfo once, as that reduces the
|
||||
// size of both the generated source code and the compiled extension
|
||||
// module. The parameters at this level are just named arg1, arg2, etc
|
||||
// so we generate an arginfo name with the number of parameters and a
|
||||
// bitmap value saying which (if any) are passed by reference.
|
||||
ParmList *l = Getattr(n, "parms");
|
||||
unsigned long bitmap = 0, bit = 1;
|
||||
bool overflowed = false;
|
||||
bool skip_this = has_this;
|
||||
for (Parm *p = l; p; p = Getattr(p, "tmap:in:next")) {
|
||||
if (skip_this) {
|
||||
skip_this = false;
|
||||
continue;
|
||||
// so the arginfo will be the same for any function with the same number
|
||||
// of parameters and (if present) PHP type declarations for parameters and
|
||||
// return type.
|
||||
//
|
||||
// We generate the arginfo we want (taking care to normalise, e.g. the
|
||||
// lists of types are unique and in sorted order), then use the
|
||||
// arginfo_used Hash to see if we've already generated it.
|
||||
|
||||
// Don't add a return type declaration for a constructor (because there
|
||||
// is no return type as far as PHP is concerned).
|
||||
String *out_phptype = NULL;
|
||||
String *out_phpclasses = NewStringEmpty();
|
||||
if (!Equal(fname, "__construct")) {
|
||||
String *php_type_flag = GetFlagAttr(n, "feature:php:type");
|
||||
if (Equal(php_type_flag, "1") ||
|
||||
(php_type_flag && !Getattr(n, "directorNode"))) {
|
||||
// We provide a simple way to generate PHP return type declarations
|
||||
// except for directed methods. The point of directors is to allow
|
||||
// subclassing in the target language, and if the wrapped method has
|
||||
// a return type declaration then an overriding method in user code
|
||||
// needs to have a compatible declaration.
|
||||
//
|
||||
// The upshot of this is that enabling return type declarations for
|
||||
// existing bindings would break compatibility with user code written
|
||||
// for an older version. For parameters however the situation is
|
||||
// different because if the parent class declares types for parameters
|
||||
// a subclass overriding the function will be compatible whether it
|
||||
// declares them or not.
|
||||
//
|
||||
// directorNode being present seems to indicate if this method or one
|
||||
// it inherits from is directed, which is what we care about here.
|
||||
// Using (!is_member_director(n)) would get it wrong for testcase
|
||||
// director_frob.
|
||||
out_phptype = phptypes.get_phptype(0, out_phpclasses);
|
||||
}
|
||||
}
|
||||
|
||||
// ### in arginfo_code will be replaced with the id once that is known.
|
||||
String *arginfo_code = NewStringEmpty();
|
||||
if (out_phptype) {
|
||||
if (Len(out_phpclasses)) {
|
||||
Replace(out_phpclasses, "\\", "\\\\", DOH_REPLACE_ANY);
|
||||
Printf(arginfo_code, "ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(swig_arginfo_###, 0, %d, %s, %s)\n", num_required, out_phpclasses, out_phptype);
|
||||
} else {
|
||||
Printf(arginfo_code, "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(swig_arginfo_###, 0, %d, %s)\n", num_required, out_phptype);
|
||||
}
|
||||
} else {
|
||||
Printf(arginfo_code, "ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_###, 0, 0, %d)\n", num_required);
|
||||
}
|
||||
|
||||
int param_count = 0;
|
||||
for (Parm *p = l; p; p = Getattr(p, "tmap:in:next")) {
|
||||
String *tmap_in_numinputs = Getattr(p, "tmap:in:numinputs");
|
||||
// tmap:in:numinputs is unset for varargs, which we don't count here.
|
||||
if (!tmap_in_numinputs || Equal(tmap_in_numinputs, "0")) {
|
||||
/* Ignored parameter */
|
||||
continue;
|
||||
}
|
||||
if (GetFlag(p, "tmap:in:byref")) {
|
||||
bitmap |= bit;
|
||||
if (bit == 0) overflowed = true;
|
||||
}
|
||||
bit <<= 1;
|
||||
}
|
||||
int num_arguments = emit_num_arguments(l);
|
||||
int num_required = emit_num_required(l);
|
||||
if (has_this) {
|
||||
--num_arguments;
|
||||
--num_required;
|
||||
}
|
||||
String *arginfo_code;
|
||||
if (overflowed) {
|
||||
// We overflowed the bitmap so just generate a unique name - this only
|
||||
// happens for a function with more parameters than bits in a long
|
||||
// where a high numbered parameter is passed by reference, so should be
|
||||
// rare in practice.
|
||||
static int overflowed_counter = 0;
|
||||
arginfo_code = NewStringf("z%d", ++overflowed_counter);
|
||||
} else if (bitmap == 0) {
|
||||
// No parameters passed by reference.
|
||||
if (num_required == num_arguments) {
|
||||
arginfo_code = NewStringf("%d", num_arguments);
|
||||
} else {
|
||||
arginfo_code = NewStringf("%d_%d", num_required, num_arguments);
|
||||
}
|
||||
} else {
|
||||
if (num_required == num_arguments) {
|
||||
arginfo_code = NewStringf("%d_r%lx", num_arguments, bitmap);
|
||||
} else {
|
||||
arginfo_code = NewStringf("%d_%d_r%lx", num_required, num_arguments, bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetFlag(arginfo_used, arginfo_code)) {
|
||||
// Not had this one before so emit it.
|
||||
SetFlag(arginfo_used, arginfo_code);
|
||||
Printf(s_arginfo, "ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_%s, 0, 0, %d)\n", arginfo_code, num_required);
|
||||
bool skip_this = has_this;
|
||||
int param_count = 0;
|
||||
for (Parm *p = l; p; p = Getattr(p, "tmap:in:next")) {
|
||||
if (skip_this) {
|
||||
skip_this = false;
|
||||
continue;
|
||||
}
|
||||
String *tmap_in_numinputs = Getattr(p, "tmap:in:numinputs");
|
||||
// tmap:in:numinputs is unset for varargs, which we don't count here.
|
||||
if (!tmap_in_numinputs || Equal(tmap_in_numinputs, "0")) {
|
||||
/* Ignored parameter */
|
||||
continue;
|
||||
}
|
||||
Printf(s_arginfo, " ZEND_ARG_INFO(%d,arg%d)\n", GetFlag(p, "tmap:in:byref"), ++param_count);
|
||||
++param_count;
|
||||
|
||||
String *phpclasses = NewStringEmpty();
|
||||
String *phptype = NULL;
|
||||
if (GetFlag(n, "feature:php:type")) {
|
||||
phptypes.get_phptype(param_count, phpclasses);
|
||||
}
|
||||
|
||||
int byref;
|
||||
if (!dispatch) {
|
||||
byref = GetFlag(p, "tmap:in:byref");
|
||||
if (byref) phptypes.set_byref(param_count);
|
||||
} else {
|
||||
// If any overload takes a particular parameter by reference then the
|
||||
// dispatch function also needs to take that parameter by reference.
|
||||
byref = phptypes.get_byref(param_count);
|
||||
}
|
||||
|
||||
// FIXME: Should we be doing byref for return value as well?
|
||||
|
||||
if (phptype) {
|
||||
if (Len(phpclasses)) {
|
||||
// We need to double any backslashes (which are PHP namespace
|
||||
// separators) in the PHP class names as they get turned into
|
||||
// C strings by the ZEND_ARG_OBJ_TYPE_MASK macro.
|
||||
Replace(phpclasses, "\\", "\\\\", DOH_REPLACE_ANY);
|
||||
Printf(arginfo_code, " ZEND_ARG_OBJ_TYPE_MASK(%d,arg%d,%s,%s,NULL)\n", byref, param_count, phpclasses, phptype);
|
||||
} else {
|
||||
Printf(arginfo_code, " ZEND_ARG_TYPE_MASK(%d,arg%d,%s,NULL)\n", byref, param_count, phptype);
|
||||
}
|
||||
} else {
|
||||
Printf(arginfo_code, " ZEND_ARG_INFO(%d,arg%d)\n", byref, param_count);
|
||||
}
|
||||
Printf(s_arginfo, "ZEND_END_ARG_INFO()\n");
|
||||
}
|
||||
Printf(arginfo_code, "ZEND_END_ARG_INFO()\n");
|
||||
|
||||
String *arginfo_id_new = Getattr(n, "sym:name");
|
||||
String *arginfo_id = Getattr(arginfo_used, arginfo_code);
|
||||
if (arginfo_id) {
|
||||
Printf(s_arginfo, "#define swig_arginfo_%s swig_arginfo_%s\n", arginfo_id_new, arginfo_id);
|
||||
} else {
|
||||
// Not had this arginfo before.
|
||||
Setattr(arginfo_used, arginfo_code, arginfo_id_new);
|
||||
arginfo_code = Copy(arginfo_code);
|
||||
Replace(arginfo_code, "###", arginfo_id_new, DOH_REPLACE_FIRST);
|
||||
Append(s_arginfo, arginfo_code);
|
||||
}
|
||||
Delete(arginfo_code);
|
||||
arginfo_code = NULL;
|
||||
|
||||
String *s = cs_entry;
|
||||
if (!s) s = s_entry;
|
||||
if (cname && Cmp(Getattr(n, "storage"), "friend") != 0) {
|
||||
Printf(all_cs_entry, " PHP_ME(%s%s,%s,swig_arginfo_%s,%s)\n", prefix, cname, fname, arginfo_code, modes);
|
||||
Printf(all_cs_entry, " PHP_ME(%s%s,%s,swig_arginfo_%s,%s)\n", prefix, cname, fname, arginfo_id_new, modes);
|
||||
} else {
|
||||
if (overload) {
|
||||
if (dispatch) {
|
||||
if (wrap_nonclass_global) {
|
||||
Printf(s, " ZEND_NAMED_FE(%(lower)s,%s,swig_arginfo_%s)\n", Getattr(n, "sym:name"), fname, arginfo_code);
|
||||
Printf(s, " ZEND_NAMED_FE(%(lower)s,%s,swig_arginfo_%s)\n", Getattr(n, "sym:name"), fname, arginfo_id_new);
|
||||
}
|
||||
|
||||
if (wrap_nonclass_fake_class) {
|
||||
(void)fake_class_name();
|
||||
Printf(fake_cs_entry, " ZEND_NAMED_ME(%(lower)s,%s,swig_arginfo_%s,ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)\n", Getattr(n, "sym:name"), fname, arginfo_code);
|
||||
Printf(fake_cs_entry, " ZEND_NAMED_ME(%(lower)s,%s,swig_arginfo_%s,ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)\n", Getattr(n, "sym:name"), fname, arginfo_id_new);
|
||||
}
|
||||
} else {
|
||||
if (wrap_nonclass_global) {
|
||||
Printf(s, " PHP_FE(%s,swig_arginfo_%s)\n", fname, arginfo_code);
|
||||
Printf(s, " PHP_FE(%s,swig_arginfo_%s)\n", fname, arginfo_id_new);
|
||||
}
|
||||
|
||||
if (wrap_nonclass_fake_class) {
|
||||
String *fake_class = fake_class_name();
|
||||
Printf(fake_cs_entry, " PHP_ME(%s,%s,swig_arginfo_%s,ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)\n", fake_class, fname, arginfo_code);
|
||||
Printf(fake_cs_entry, " PHP_ME(%s,%s,swig_arginfo_%s,ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)\n", fake_class, fname, arginfo_id_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
Delete(arginfo_code);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
|
@ -784,27 +913,29 @@ public:
|
|||
base_class = NULL;
|
||||
}
|
||||
|
||||
// Ensure arginfo_1 and arginfo_2 exist.
|
||||
if (!GetFlag(arginfo_used, "1")) {
|
||||
SetFlag(arginfo_used, "1");
|
||||
static bool generated_magic_arginfo = false;
|
||||
if (!generated_magic_arginfo) {
|
||||
// Create arginfo entries for __get, __set and __isset.
|
||||
Append(s_arginfo,
|
||||
"ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_1, 0, 0, 1)\n"
|
||||
" ZEND_ARG_INFO(0,arg1)\n"
|
||||
"ZEND_BEGIN_ARG_INFO_EX(swig_magic_arginfo_get, 0, 0, 1)\n"
|
||||
" ZEND_ARG_TYPE_MASK(0,arg1,MAY_BE_STRING,NULL)\n"
|
||||
"ZEND_END_ARG_INFO()\n");
|
||||
}
|
||||
if (!GetFlag(arginfo_used, "2")) {
|
||||
SetFlag(arginfo_used, "2");
|
||||
Append(s_arginfo,
|
||||
"ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_2, 0, 0, 2)\n"
|
||||
" ZEND_ARG_INFO(0,arg1)\n"
|
||||
"ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(swig_magic_arginfo_set, 0, 1, MAY_BE_VOID)\n"
|
||||
" ZEND_ARG_TYPE_MASK(0,arg1,MAY_BE_STRING,NULL)\n"
|
||||
" ZEND_ARG_INFO(0,arg2)\n"
|
||||
"ZEND_END_ARG_INFO()\n");
|
||||
Append(s_arginfo,
|
||||
"ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(swig_magic_arginfo_isset, 0, 1, MAY_BE_BOOL)\n"
|
||||
" ZEND_ARG_TYPE_MASK(0,arg1,MAY_BE_STRING,NULL)\n"
|
||||
"ZEND_END_ARG_INFO()\n");
|
||||
generated_magic_arginfo = true;
|
||||
}
|
||||
|
||||
Wrapper *f = NewWrapper();
|
||||
|
||||
Printf(f_h, "PHP_METHOD(%s%s,__set);\n", prefix, class_name);
|
||||
Printf(all_cs_entry, " PHP_ME(%s%s,__set,swig_arginfo_2,ZEND_ACC_PUBLIC)\n", prefix, class_name);
|
||||
Printf(all_cs_entry, " PHP_ME(%s%s,__set,swig_magic_arginfo_set,ZEND_ACC_PUBLIC)\n", prefix, class_name);
|
||||
Printf(f->code, "PHP_METHOD(%s%s,__set) {\n", prefix, class_name);
|
||||
|
||||
Printf(f->code, " swig_object_wrapper *arg = SWIG_Z_FETCH_OBJ_P(ZEND_THIS);\n");
|
||||
|
@ -842,7 +973,7 @@ public:
|
|||
|
||||
|
||||
Printf(f_h, "PHP_METHOD(%s%s,__get);\n", prefix, class_name);
|
||||
Printf(all_cs_entry, " PHP_ME(%s%s,__get,swig_arginfo_1,ZEND_ACC_PUBLIC)\n", prefix, class_name);
|
||||
Printf(all_cs_entry, " PHP_ME(%s%s,__get,swig_magic_arginfo_get,ZEND_ACC_PUBLIC)\n", prefix, class_name);
|
||||
Printf(f->code, "PHP_METHOD(%s%s,__get) {\n",prefix, class_name);
|
||||
|
||||
Printf(f->code, " swig_object_wrapper *arg = SWIG_Z_FETCH_OBJ_P(ZEND_THIS);\n");
|
||||
|
@ -875,7 +1006,7 @@ public:
|
|||
|
||||
|
||||
Printf(f_h, "PHP_METHOD(%s%s,__isset);\n", prefix, class_name);
|
||||
Printf(all_cs_entry, " PHP_ME(%s%s,__isset,swig_arginfo_1,ZEND_ACC_PUBLIC)\n", prefix, class_name);
|
||||
Printf(all_cs_entry, " PHP_ME(%s%s,__isset,swig_magic_arginfo_isset,ZEND_ACC_PUBLIC)\n", prefix, class_name);
|
||||
Printf(f->code, "PHP_METHOD(%s%s,__isset) {\n",prefix, class_name);
|
||||
|
||||
Printf(f->code, " swig_object_wrapper *arg = SWIG_Z_FETCH_OBJ_P(ZEND_THIS);\n");
|
||||
|
@ -994,6 +1125,12 @@ public:
|
|||
return SWIG_ERROR;
|
||||
}
|
||||
|
||||
if (!Getattr(n, "sym:previousSibling")) {
|
||||
// First function of an overloaded group or a function which isn't part
|
||||
// of a group so reset the phptype information.
|
||||
phptypes.reset();
|
||||
}
|
||||
|
||||
if (constructor) {
|
||||
wname = NewString("__construct");
|
||||
} else if (wrapperType == membervar) {
|
||||
|
@ -1077,10 +1214,6 @@ public:
|
|||
/* Attach standard typemaps */
|
||||
|
||||
emit_attach_parmmaps(l, f);
|
||||
// Not issued for overloaded functions.
|
||||
if (!overloaded && !static_getter) {
|
||||
create_command(class_name, wname, n, false, modes);
|
||||
}
|
||||
|
||||
if (wrapperType == memberfn || wrapperType == membervar) {
|
||||
// Assign "this" to arg1 and remove first entry from ParmList l.
|
||||
|
@ -1164,6 +1297,8 @@ public:
|
|||
continue;
|
||||
}
|
||||
|
||||
phptypes.process_phptype(p, i + 1, "tmap:in:phptype");
|
||||
|
||||
String *source = NewStringf("args[%d]", i);
|
||||
Replaceall(tm, "$input", source);
|
||||
Setattr(p, "emit:input", source);
|
||||
|
@ -1247,6 +1382,8 @@ public:
|
|||
}
|
||||
emit_return_variable(n, d, f);
|
||||
|
||||
phptypes.process_phptype(n, 0, "tmap:out:phptype");
|
||||
|
||||
if (outarg) {
|
||||
Printv(f->code, outarg, NIL);
|
||||
}
|
||||
|
@ -1290,10 +1427,15 @@ public:
|
|||
Wrapper_print(f, s_wrappers);
|
||||
DelWrapper(f);
|
||||
f = NULL;
|
||||
wname = NULL;
|
||||
|
||||
if (overloaded && !Getattr(n, "sym:nextSibling")) {
|
||||
dispatchFunction(n, constructor);
|
||||
if (overloaded) {
|
||||
if (!Getattr(n, "sym:nextSibling")) {
|
||||
dispatchFunction(n, constructor);
|
||||
}
|
||||
} else {
|
||||
if (!static_getter) {
|
||||
create_command(class_name, wname, n, false, modes);
|
||||
}
|
||||
}
|
||||
|
||||
return SWIG_OK;
|
||||
|
@ -2154,6 +2296,82 @@ public:
|
|||
|
||||
static PHP *maininstance = 0;
|
||||
|
||||
void PHPTypes::process_phptype(Node *n, int key, const String_or_char *attribute_name) {
|
||||
|
||||
while (Len(merged_types) <= key) {
|
||||
Append(merged_types, NewList());
|
||||
}
|
||||
|
||||
String *phptype = Getattr(n, attribute_name);
|
||||
if (!phptype || Len(phptype) == 0) {
|
||||
// There's no type declaration, so any merged version has no type declaration.
|
||||
//
|
||||
// Use a DOH None object as a marker to indicate there's no type
|
||||
// declaration for this parameter/return value (you can't store NULL as a
|
||||
// value in a DOH List).
|
||||
Setitem(merged_types, key, None);
|
||||
return;
|
||||
}
|
||||
|
||||
DOH *merge_list = Getitem(merged_types, key);
|
||||
if (merge_list == None) return;
|
||||
|
||||
List *types = Split(phptype, '|', -1);
|
||||
String *first_type = Getitem(types, 0);
|
||||
if (Char(first_type)[0] == '?') {
|
||||
if (Len(types) > 1) {
|
||||
Printf(stderr, "warning: Invalid phptype: '%s' (can't use ? and | together)\n", phptype);
|
||||
}
|
||||
// Treat `?foo` just like `foo|null`.
|
||||
Append(types, "null");
|
||||
Setitem(types, 0, NewString(Char(first_type) + 1));
|
||||
}
|
||||
|
||||
SortList(types, NULL);
|
||||
String *prev = NULL;
|
||||
for (Iterator i = First(types); i.item; i = Next(i)) {
|
||||
if (prev && Equal(prev, i.item)) {
|
||||
Printf(stderr, "warning: Invalid phptype: '%s' (duplicate entry for '%s')\n", phptype, i.item);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key > 0 && Equal(i.item, "void")) {
|
||||
// Reject void for parameter type.
|
||||
Printf(stderr, "warning: Invalid phptype: '%s' ('%s' can't be used as a parameter phptype)\n", phptype, i.item);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Equal(i.item, "SWIGTYPE")) {
|
||||
String *type = Getattr(n, "type");
|
||||
Node *class_node = maininstance->classLookup(type);
|
||||
if (class_node) {
|
||||
// FIXME: Prefix classname with a backslash to prevent collisions
|
||||
// with built-in types? Or are non of those valid anyway and so will
|
||||
// have been renamed at this point?
|
||||
Append(merge_list, Getattr(class_node, "sym:name"));
|
||||
} else {
|
||||
// SWIG wraps a pointer to a non-object type as an object in a PHP
|
||||
// class named based on the SWIG-mangled C/C++ type.
|
||||
//
|
||||
// FIXME: We should check this is actually a known pointer to
|
||||
// non-object type so we complain about `phptype="SWIGTYPE"` being
|
||||
// used for PHP types like `int` or `string` (currently this only
|
||||
// fails at runtime and the error isn't very helpful). We could
|
||||
// check the condition
|
||||
//
|
||||
// zend_types && Getattr(zend_types, SwigType_manglestr(type))
|
||||
//
|
||||
// except that zend_types may not have been fully filled in when
|
||||
// we are called.
|
||||
Append(merge_list, NewStringf("SWIG\\%s", SwigType_manglestr(type)));
|
||||
}
|
||||
} else {
|
||||
Append(merge_list, i.item);
|
||||
}
|
||||
prev = i.item;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect non-class pointer types from the type table so we can set up PHP
|
||||
// classes for them later.
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue