diff --git a/Examples/test-suite/php/default_args_runme.php b/Examples/test-suite/php/default_args_runme.php new file mode 100644 index 000000000..944426e29 --- /dev/null +++ b/Examples/test-suite/php/default_args_runme.php @@ -0,0 +1,141 @@ +blah(), true, "EnumClass::blah() default arguments don't work"); + +$de = new DerivedEnumClass(); +$de->accelerate(); +$de->accelerate(EnumClass::SLOW); + +check::equal(Statics::staticMethod(), 60, "Statics::staticMethod()"); + +check::equal(cfunc1(1), 2.0, "cfunc1(1)"); + +check::equal(cfunc2(1), 3.0, "cfunc2(1)"); + +check::equal(cfunc3(1), 4.0, "cfunc3(1)"); + +$f = new Foo(); + +$f->newname(); +$f->newname(1); +$f->defaulted1(); +$f->defaulted2(); + +check::equal($f->double_if_void_ptr_is_null(2, Null), 4, "\$f->double_if_void_ptr_is_null(2, Null)"); + +check::equal($f->double_if_void_ptr_is_null(3), 6, "\$f->double_if_void_ptr_is_null(3)"); + +check::equal($f->double_if_void_ptr_is_null(4, Null), 8, "\$f->double_if_void_ptr_is_null(4, Null)"); + +check::equal($f->double_if_void_ptr_is_null(5, Null), 10, "\$f->double_if_void_ptr_is_null(5, Null)"); + +check::equal($f->double_if_void_ptr_is_null(6, Null), 12, "\$f->double_if_void_ptr_is_null(6, Null)"); + +check::equal($f->double_if_void_ptr_is_null(7), 14, "\$f->double_if_void_ptr_is_null(7)"); + +try { + $f = new Foo(1); + check::fail("Foo::Foo ignore is not working"); +} catch (ArgumentCountError $e) { +} + +try { + $f = new Foo(1, 2); + check::fail("Foo::Foo ignore is not working"); +} catch (ArgumentCountError $e) { +} + +try { + $f = new Foo(1, 2, 3); + check::fail("Foo::Foo ignore is not working"); +} catch (ArgumentCountError $e) { +} + +try { + $m = $f->meth(1); + check::fail("Foo::meth ignore is not working"); +} catch (Error $e) { +} + +try { + $m = $f->meth(1, 2); + check::fail("Foo::meth ignore is not working"); +} catch (Error $e) { +} + +try { + $m = $f->meth(1, 2, 3); + check::fail("Foo::meth ignore is not working"); +} catch (Error $e) { +} + +check::equal(Klass::inc(100, new Klass(22))->val, 122, "Klass::inc failed"); + +check::equal(klass::inc(100)->val, 99, "klass::inc failed"); + +check::equal(klass::inc()->val, 0, "klass::inc failed"); + +$tricky = new TrickyInPython(); +check::equal($tricky->value_m1(10), -1, "trickyvalue_m1 failed"); +check::equal($tricky->value_m1(10, 10), 10, "trickyvalue_m1 failed"); +check::equal($tricky->value_0xabcdef(10), 0xabcdef, "trickyvalue_0xabcdef failed"); +check::equal($tricky->value_0644(10), 420, "trickyvalue_0644 failed"); +check::equal($tricky->value_perm(10), 420, "trickyvalue_perm failed"); +check::equal($tricky->value_m01(10), -1, "trickyvalue_m01 failed"); +check::equal($tricky->booltest2(), True, "booltest2 failed"); + +check::equal($tricky->max_32bit_int1(), 0x7FFFFFFF, "max_32bit_int1 failed"); +check::equal($tricky->min_32bit_int1(), -2147483648, "min_32bit_int1 failed"); +check::equal($tricky->max_32bit_int2(), 0x7FFFFFFF, "max_32bit_int2 failed"); + +$tricky->too_big_32bit_int1(); +$tricky->too_small_32bit_int1(); +$tricky->too_big_32bit_int2(); +$tricky->too_small_32bit_int2(); + +seek(); +seek(10); + +check::equal(booltest(), True, "booltest failed"); + +check::equal(slightly_off_square(10), 102, "slightly_off_square(10)"); + +check::equal(slightly_off_square(), 291, "slightly_off_square()"); + +check::equal(chartest1(), "x", "chartest1()"); + +check::equal(chartest2(), "\0", "chartest2()"); + +check::equal(chartest3(), "\1", "chartest3()"); + +check::equal(chartest4(), "\n", "chartest4()"); + +check::equal(chartest5(), "B", "chartest5()"); + +check::equal(chartest6(), "C", "chartest6()"); + +if (PHP_MAJOR_VERSION >= 8) { + // Regression test for bug in initial implementation of PHP type declarations. + $p = (new ReflectionMethod('TrickyInPython', 'value_m1'))->getParameters(); + // empty array in buggy version + check::equal(count($p), 2, "Expected 2 parameters"); + check::equal((string)$p[0]->getType(), 'int', "Expected int parameter"); + check::equal((string)$p[1]->getType(), 'int', "Expected int parameter"); + + $p = (new ReflectionMethod('EnumClass', 'blah'))->getParameters(); + // empty array in buggy version + check::equal(count($p), 2, "Expected 2 parameters"); + check::equal((string)$p[0]->getType(), 'int', "Expected int parameter"); + check::equal((string)$p[1]->getType(), 'int', "Expected int parameter"); +} + +check::done(); diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx index faf4fe070..d0c337a6a 100644 --- a/Source/Modules/php.cxx +++ b/Source/Modules/php.cxx @@ -13,6 +13,7 @@ */ #include "swigmod.h" +#include #include #include @@ -269,12 +270,19 @@ public: while (Len(byref) <= key) { Append(byref, None); } + // If any overload takes a particular parameter by reference then the + // dispatch function also needs to take that parameter by reference so + // we can just set unconditionally here. Setitem(byref, key, ""); // Just needs to be something != None. } int get_byref(int key) const { return byref && key < Len(byref) && Getitem(byref, key) != None; } + + int size() const { + return std::max(Len(merged_types), Len(byref)); + } }; static PHPTypes *phptypes = NULL; @@ -759,36 +767,12 @@ public: Printf(arginfo_code, "ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_###, 0, 0, %d)\n", num_required); } - if (Getattr(n, "defaultargs")) { - // Include parameters with default values in the arginfo. - l = Getattr(Getattr(n, "defaultargs"), "parms"); - } - 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; - } - - ++param_count; - + int phptypes_size = phptypes->size(); + for (int param_count = 1; param_count < phptypes_size; ++param_count) { String *phpclasses = NewStringEmpty(); - String *phptype = NULL; - if (GetFlag(n, "feature:php:type")) { - phptype = phptypes->get_phptype(param_count, phpclasses); - } + String *phptype = 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); - } + int byref = phptypes->get_byref(param_count); // FIXME: Should we be doing byref for return value as well? @@ -1356,6 +1340,7 @@ public: } phptypes->process_phptype(p, i + 1, "tmap:in:phptype"); + if (GetFlag(p, "tmap:in:byref")) phptypes->set_byref(i + 1); String *source = NewStringf("args[%d]", i); Replaceall(tm, "$input", source);