So I have the following C++
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
int hello(char *str);
int hello(char *str) {
cout << "Hello World: " << str << endl;
return 0;
}
And the following swig interface
%module sphp
%{
extern int hello(char *str);
%}
extern int hello(char *str);
And I can compile and use this in php,
php> hello("testing!");
This all is wicked!
Only problem is
php> hello(3);
is still valid. I don't want this, it seems swig silently casts types
/*@SWIG:/usr/share/swig2.0/php/utils.i,62,CONVERT_STRING_IN@*/
if ((*args[0])->type==IS_NULL) {
arg1 = (char *) 0;
} else {
convert_to_string_ex(args[0]);
arg1 = (char *) Z_STRVAL_PP(args[0]);
}
/*@SWIG@*/;
Now I don't want to be editing the wrapper, because its auto generated. Is there a way I can turn off this silent conversion, so that hello(3)
will throw exceptions or errors, or can I give hello
a hint about the type of the php argument it was originally passed?
Sadly, because of how the wrapper is generated, you can't get rid of the casting completely. You can however, intercept basic datatypes and redirect them to a template function like so:
%module sphp
%{
#include <iostream>
extern int hello(char *str);
template<class T>
int hello(const T &)
{
std::cout << "unsupported data type" << std::endl;
}
%}
extern int hello(char *str);
template<class T>
int hello(const T &);
%template(hello) hello<int>;
To intercept more data types, simply add a new operator overload:
%template(hello) hello<double>;
Update:
Here's a more difficult approach that works by overriding SWIG's typemaps. This is taken from SWIG's PHP typemaps and modified to prevent it from casting values.
%module sphp
%{
extern int hello(char *str);
%}
%typemap(in) char *
{
if ((*$input)->type != IS_STRING)
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected string");
$1 = ($1_ltype) Z_STRVAL_PP($input);
}
%typemap(in) (char *STRING, int LENGTH), (char *STRING, size_t LENGTH) {
if ((*$input)->type != IS_STRING)
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected string");
$1 = ($1_ltype) Z_STRVAL_PP($input);
$2 = ($2_ltype) Z_STRLEN_PP($input);
}
extern int hello(char *str);
Output:
php > include ("sphp.php");
php > hello("test");
Hello World: test
php > hello(3);
PHP Fatal error: Type error in argument 1 of hello. Expected string in php shell code on line 1
php > hello([]);
PHP Fatal error: Type error in argument 1 of hello. Expected string in php shell code on line 1
php >
This is more tedious since you'll have to override every single type in the same manner if you want to get rid of automatic argument casting completely, on the other hand it gives you more control over the behaviour of argument forwarding.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With