[php] Adjust #required params for subclass methods
If the same method name is implemented in a parent class then the subclass can't have more required parameters than that or else we get a compatibility error when the module is loaded. The testsuite wasn't catching this problem because it was no longer trying to load the modules for testcases without _runme.php, because the mechanism to do that relied on there being a generated .php wrapper, which we no longer have by default. Fix that to provide a regression test for this fix. See #2151
This commit is contained in:
parent
b41fede827
commit
9cdf46e8c8
5 changed files with 29 additions and 15 deletions
|
|
@ -1071,7 +1071,7 @@ php_cpp: $(SRCDIR_SRCS)
|
|||
# -----------------------------------------------------------------
|
||||
|
||||
php_run:
|
||||
$(RUNTOOL) $(PHP) -n -d extension_dir=. -d extension=$(PHP_EXTENSION) -d display_errors=stderr -r 'set_error_handler(function($$n,$$s,$$f,$$l){if($$f!==Null){print$$f;if($$l!==Null)print":$$l";print": ";}print"$$s\n";exit(1);});include($$argv[1]);' $(PHP_SCRIPT) $(RUNPIPE)
|
||||
$(RUNTOOL) $(PHP) -n -d extension_dir=. -d extension=$(PHP_EXTENSION) -d display_errors=stderr -r 'set_error_handler(function($$n,$$s,$$f,$$l){if($$f!==Null){print$$f;if($$l!==Null)print":$$l";print": ";}print"$$s\n";exit(1);});if(strlen($$argv[1]))include($$argv[1]);' '$(PHP_SCRIPT)' $(RUNPIPE)
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Version display
|
||||
|
|
|
|||
|
|
@ -68,18 +68,18 @@ missingtests: missingcpptests missingctests
|
|||
@echo ' $(MULTI_CPP_TEST_CASES) '|grep -F -v ' $* ' >/dev/null ||\
|
||||
$(MAKE) $*.multicpptest
|
||||
|
||||
# Runs the testcase. Tries to run testcase_runme.php, and if that's not
|
||||
# found, runs testcase.php, except for multicpptests.
|
||||
# Runs the testcase. Tries to run testcase_runme.php, and if that's not found,
|
||||
# at least test that the module loads without errors, except for multicpptests.
|
||||
run_testcase = \
|
||||
if [ -f $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ]; then \
|
||||
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile PHP_EXTENSION=$(TARGETPREFIX)$*@PHP_SO@ PHP_SCRIPT=$(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) RUNTOOL='$(RUNTOOL)' php_run; \
|
||||
elif [ -f $(SCRIPTDIR)/$(SCRIPTPREFIX)$*.php -a ! -f $(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$*.list ]; then \
|
||||
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile PHP_EXTENSION=$(TARGETPREFIX)$*@PHP_SO@ PHP_SCRIPT=$(SCRIPTDIR)/$(SCRIPTPREFIX)$*.php RUNTOOL='$(RUNTOOL)' php_run; \
|
||||
elif [ ! -f $(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$*.list ]; then \
|
||||
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile PHP_EXTENSION=$(TARGETPREFIX)$*@PHP_SO@ PHP_SCRIPT= RUNTOOL='$(RUNTOOL)' php_run; \
|
||||
fi
|
||||
|
||||
# Clean: remove the generated .php file
|
||||
# Clean: remove the generated PHP-specific files
|
||||
%.clean:
|
||||
@rm -f $*.php php_$*.h
|
||||
@rm -f php_$*.h
|
||||
|
||||
clean:
|
||||
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile SRCDIR='$(SRCDIR)' php_clean
|
||||
|
|
|
|||
|
|
@ -22,19 +22,19 @@ check::equal($a->ping(), "MyFoo::ping()", "MyFoo::ping failed");
|
|||
check::equal($a->pong(), "Foo::pong();MyFoo::ping()", "MyFoo::pong failed");
|
||||
|
||||
class MyExample1 extends Example1 {
|
||||
function Color($r, $g, $b) {
|
||||
function Color($r, $g = NULL, $b = NULL) {
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
|
||||
class MyExample2 extends Example1 {
|
||||
function Color($r, $g, $b) {
|
||||
function Color($r, $g = NULL, $b = NULL) {
|
||||
return $g;
|
||||
}
|
||||
}
|
||||
|
||||
class MyExample3 extends Example1 {
|
||||
function Color($r, $g, $b) {
|
||||
function Color($r, $g = NULL, $b = NULL) {
|
||||
return $b;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class MyFoo extends Foo {
|
|||
return $v;
|
||||
}
|
||||
|
||||
function vsecond($v1, $v2) {
|
||||
function vsecond($v1, $v2 = NULL) {
|
||||
return $v2;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,17 +218,31 @@ class PHPTypes {
|
|||
// the dispatch function. If NULL, no parameters are passed by reference.
|
||||
List *byref;
|
||||
|
||||
// Used to clamp the required number of parameters in the arginfo to be
|
||||
// compatible with any parent class version of the method.
|
||||
int required_clamp;
|
||||
|
||||
public:
|
||||
PHPTypes() : merged_types(NewList()), byref(NULL) { }
|
||||
PHPTypes(int num_required)
|
||||
: merged_types(NewList()),
|
||||
byref(NULL),
|
||||
required_clamp(num_required) { }
|
||||
|
||||
PHPTypes(const PHPTypes *o)
|
||||
: merged_types(Copy(o->merged_types)), byref(Copy(o->byref)) { }
|
||||
: merged_types(Copy(o->merged_types)),
|
||||
byref(Copy(o->byref)),
|
||||
required_clamp(o->required_clamp) { }
|
||||
|
||||
~PHPTypes() {
|
||||
Delete(merged_types);
|
||||
Delete(byref);
|
||||
}
|
||||
|
||||
int adjust_num_required(int num_required) {
|
||||
required_clamp = std::min(num_required, required_clamp);
|
||||
return required_clamp;
|
||||
}
|
||||
|
||||
// key is 0 for return type, or >= 1 for parameters numbered from 1
|
||||
void process_phptype(Node *n, int key, const String_or_char *attribute_name);
|
||||
|
||||
|
|
@ -712,7 +726,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
int num_required = emit_num_required(l);
|
||||
int num_required = phptypes->adjust_num_required(emit_num_required(l));
|
||||
|
||||
// We want to only emit each different arginfo once, as that reduces the
|
||||
// size of both the generated source code and the compiled extension
|
||||
|
|
@ -1214,7 +1228,7 @@ public:
|
|||
}
|
||||
}
|
||||
if (!phptypes) {
|
||||
phptypes = new PHPTypes();
|
||||
phptypes = new PHPTypes(emit_num_required(l));
|
||||
}
|
||||
if (class_name) {
|
||||
SetVoid(all_phptypes, NewStringf("%s:%s", class_name, wname), phptypes);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue