summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlly Betts <olly@survex.com>2023-04-21 17:43:32 +1200
committerOlly Betts <olly@survex.com>2023-04-21 17:50:25 +1200
commit6cd19ba92612dfca3ac0a66740050bf539263543 (patch)
treec8d311e721091e00da9bba570804f84e50b9116a
parent903b3d5ac3908ade77623144a5c33cbcbfe9ce59 (diff)
downloadswig-6cd19ba92612dfca3ac0a66740050bf539263543.tar.gz
[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.
-rw-r--r--CHANGES.current8
-rw-r--r--Examples/test-suite/li_std_string.i20
-rw-r--r--Examples/test-suite/php/li_std_string_runme.php18
-rw-r--r--Lib/php/std_string.i46
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 <std_string.i>
-#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 <string>
%}
+/* 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;
+
}