[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:
Olly Betts 2022-01-20 10:07:44 +13:00 committed by GitHub
commit 1f1349741f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 536 additions and 196 deletions

View file

@ -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) {

View file

@ -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;

View file

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

View file

@ -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)

View file

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

View file

@ -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*

View file

@ -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;