From 6cd19ba92612dfca3ac0a66740050bf539263543 Mon Sep 17 00:00:00 2001 From: Olly Betts Date: Fri, 21 Apr 2023 17:43:32 +1200 Subject: [php] Support INPUT,INOUT,OUTPUT for std::string& By default SWIG/PHP wraps std::string& as a pass-by-reference PHP string parameter, but sometimes such a parameter is only for input or only for output, so add support for the named typemaps that other target languages support. --- CHANGES.current | 8 +++++ Examples/test-suite/li_std_string.i | 20 +++++++++-- Examples/test-suite/php/li_std_string_runme.php | 18 ++++++++++ Lib/php/std_string.i | 46 ++++++++++++++++++++----- 4 files changed, 81 insertions(+), 11 deletions(-) diff --git a/CHANGES.current b/CHANGES.current index 588459210..f438fb647 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,14 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.2.0 (in progress) =========================== +2023-04-21: olly + [PHP] Support INPUT,INOUT,OUTPUT for std::string&. + + By default SWIG/PHP wraps std::string& as a pass-by-reference PHP + string parameter, but sometimes such a parameter is only for input + or only for output, so add support for the named typemaps that other + target languages support. + 2023-04-21: degasus #2519 Fix CanCastAsInteger range check to clear errno first to fix bogus failures for valid inputs.if errno is set. diff --git a/Examples/test-suite/li_std_string.i b/Examples/test-suite/li_std_string.i index 47a9090b7..209cf883f 100644 --- a/Examples/test-suite/li_std_string.i +++ b/Examples/test-suite/li_std_string.i @@ -1,9 +1,10 @@ %module li_std_string %include -#if defined(SWIGUTL) +#if defined(SWIGPHP) || defined(SWIGUTL) %apply std::string& INPUT { std::string &input } %apply std::string& INOUT { std::string &inout } +%apply std::string& OUTPUT { std::string &output } #endif // throw is invalid in C++17 and later, only SWIG to use it @@ -53,13 +54,28 @@ std::string& test_reference_out() { } std::string test_reference_input(std::string &input) { - return input; + // For PHP to allow checking that we haven't used the default string& + // typemap which wraps as a PHP pass-by-reference string parameter. + std::string copy = input; + input = "MODIFIED"; + return copy; } void test_reference_inout(std::string &inout) { inout += inout; } +void test_reference_output(std::string &output) { + output = "output"; +} + +#ifdef SWIGPHP +// Test PHP-specific default wrapping string& as pass-by-ref PHP string. +void test_reference_php(std::string &s) { + s += ".php"; +} +#endif + void test_throw() TESTCASE_THROW1(std::string){ static std::string x = "test_throw message"; throw x; diff --git a/Examples/test-suite/php/li_std_string_runme.php b/Examples/test-suite/php/li_std_string_runme.php index 680b7ce98..169f947a7 100644 --- a/Examples/test-suite/php/li_std_string_runme.php +++ b/Examples/test-suite/php/li_std_string_runme.php @@ -49,6 +49,24 @@ Structure::StaticMemberString2($s); check::equal(Structure::StaticMemberString2(), $s, "StaticMemberString2 test 2"); check::equal(Structure::ConstStaticMemberString(), "const static member string", "ConstStaticMemberString test"); +// Test INPUT, INOUT and OUTPUT string& typemaps: +$input = "hello"; +check::equal(li_std_string::test_reference_input($input), "hello"); +// $input should be unchanged - this check is to catch if we incorrectly used +// the default string& typemap: +check::equal($input, "hello"); +$s = li_std_string::test_reference_inout($input); +check::equal($s, "hellohello"); +// $input should be unchanged - this check is to catch if we incorrectly used +// the default string& typemap: +check::equal($input, "hello"); +check::equal(li_std_string::test_reference_output(), "output"); + +// Test default PHP wrapping of std::string& as a by-ref PHP string parameter: +$s = "byref"; +check::equal(li_std_string::test_reference_php($s), null); +check::equal($s, "byref.php"); + // This used to give "Undefined variable: r" li_std_string::test_const_reference_returning_void("foo"); diff --git a/Lib/php/std_string.i b/Lib/php/std_string.i index 2d2252d9b..0e2e1faff 100644 --- a/Lib/php/std_string.i +++ b/Lib/php/std_string.i @@ -4,17 +4,21 @@ * SWIG typemaps for std::string types * ----------------------------------------------------------------------------- */ -// ------------------------------------------------------------------------ -// std::string is typemapped by value -// This can prevent exporting methods which return a string -// in order for the user to modify it. -// However, I think I'll wait until someone asks for it... -// ------------------------------------------------------------------------ - %{ #include %} +/* std::string and const std::string& are converted to/from PHP string + * automatically. + * + * A C++ std::string& parameter is wrapped as a pass-by-reference PHP + * string parameter by default, but the INPUT/INOUT/OUTPUT typemaps + * below provide other options (see below). + * + * std::string* is not wrapped by default, but INPUT/INOUT/OUTPUT typemaps + * are provided (see below). + */ + namespace std { %naturalvar string; @@ -58,8 +62,10 @@ namespace std { $1 = &temp; %} - /* These next two handle a function which takes a non-const reference to - * a std::string and modifies the string. */ + /*************************************************************************/ + + /* These next four typemaps handle a function which takes a non-const + * reference to a std::string and modifies the string. */ %typemap(in,byref=1, phptype="string") string& ($*1_ltype temp) %{ { zval * p = Z_ISREF($input) ? Z_REFVAL($input) : &$input; @@ -85,4 +91,26 @@ namespace std { /* SWIG will apply the non-const typemap above to const string& without * this more specific typemap. */ %typemap(argout) const string& "" + + /*************************************************************************/ + + /* Alternative ways to handle string& - you can specify how to wrap based + * on the parameter name, e.g. this handles parameters named `str` as + * INOUT: + * + * %apply (std::string& INOUT) (std::string& str); + */ + + %typemap(in) string& INPUT = const string&; + %typemap(in, numinputs=0) string& OUTPUT ($*1_ltype temp) + %{ $1 = &temp; %} + %typemap(argout,fragment="t_output_helper") string& OUTPUT + { + zval o; + ZVAL_STRINGL(&o, $1->data(), $1->size()); + t_output_helper($result, &o); + } + %typemap(in) string& INOUT = const string&; + %typemap(argout) string& INOUT = string& OUTPUT; + } -- cgit v1.2.1