diff --git a/src/Generator/ClosureGenerator.php b/src/Generator/ClosureGenerator.php index e194c13b..0091701c 100644 --- a/src/Generator/ClosureGenerator.php +++ b/src/Generator/ClosureGenerator.php @@ -150,19 +150,11 @@ trait ClosureGenerator } $requiredArgCount++; } - if ($requiredArgCount > 0) { - $expected = $requiredArgCount === count($params) ? 'exactly' : 'at least'; - $message = $this->genCharPtr( - 'Too few arguments to function {closure}(), %u passed and ' . $expected . ' ' . $requiredArgCount . ' expected', - true - ); - $code .= $this->getIndent() . 'if (UNEXPECTED(php::getCallArgNum() < ' . $requiredArgCount . ')) {' . PHP_EOL; - $this->indentLevel++; - $code .= $this->getIndent() . 'php::throwExceptionEx(zend_ce_argument_count_error, 0, ' . $message . ', php::getCallArgNum());' . PHP_EOL; - $code .= $this->getIndent() . 'return php::null;' . PHP_EOL; - $this->indentLevel--; - $code .= $this->getIndent() . '}' . PHP_EOL; - } + + // Use PHP's built-in macros to check whether the number of parameters is correct. + $maxNumArgs = count($params); + $hasVariadic = $maxNumArgs > 0 ? $params[$maxNumArgs - 1]->variadic : false; + $code .= ParamCountCheckMarco::genParamCountMacroDefinition($maxNumArgs, $requiredArgCount, $hasVariadic); foreach ($params as $i => $param) { if ($param->byRef) { diff --git a/src/Generator/ParamCountCheckMarco.php b/src/Generator/ParamCountCheckMarco.php new file mode 100644 index 00000000..562ac63e --- /dev/null +++ b/src/Generator/ParamCountCheckMarco.php @@ -0,0 +1,34 @@ +argCountRequired > 0) { - $cppCode .= $this->genWrapperRequiredArgCountCheck($functionDef, $displayName); - } + // Use PHP's built-in macros to check whether the number of parameters is correct. + $maxNumArgs = count($functionDef->argInfoList); + $hasVariadic = $maxNumArgs > 0 ? $functionDef->argInfoList[$maxNumArgs - 1]->variadic : false; + $cppCode .= ParamCountCheckMarco::genParamCountMacroDefinition($maxNumArgs, $functionDef->argCountRequired, $hasVariadic); + + $callParams = ''; foreach ($functionDef->argInfoList as $k => $argInfo) { $var = 'arg_' . $argInfo->name; if ($argInfo->variadic) { @@ -3498,25 +3501,6 @@ CODE; ], true); } - private function genWrapperRequiredArgCountCheck(FunctionDef $functionDef, string $displayName): string - { - $required = $functionDef->argCountRequired; - $expected = $required === count($functionDef->argInfoList) ? 'exactly' : 'at least'; - $message = $this->genCharPtr( - 'Too few arguments to function ' . $displayName . '(), %u passed and ' . $expected . ' ' . $required . ' expected', - true - ); - - $code = $this->getIndent() . 'if (UNEXPECTED(php::getCallArgNum() < ' . $required . ')) {' . PHP_EOL; - $this->indentLevel++; - $code .= $this->getIndent() . 'php::throwExceptionEx(zend_ce_argument_count_error, 0, ' . $message . ', php::getCallArgNum());' . PHP_EOL; - $code .= $this->getIndent() . 'return;' . PHP_EOL; - $this->indentLevel--; - $code .= $this->getIndent() . '}' . PHP_EOL; - - return $code; - } - protected function genMethodWrapper(ClassDef $classDef, MethodDef $methodDef): string { $name = $classDef->getNamespacedName(); diff --git a/tests/compiler/functions/args-count.phpt b/tests/compiler/functions/args-count.phpt new file mode 100644 index 00000000..05211db5 --- /dev/null +++ b/tests/compiler/functions/args-count.phpt @@ -0,0 +1,59 @@ +--TEST-- +args count check +--FILE-- +getMessage()); + } + + try { + world(function(string $value, string $value1) { + + }); + } catch (ArgumentCountError $e) { + var_dump($e->getMessage()); + } + + try { + $callable = "variadic"; + $callable(); + } catch (ArgumentCountError $e) { + var_dump($e->getMessage()); + } + + $callable('1', 1, 2, 3, 4, 5); +} +?> +--EXPECT-- +string(43) "hello() expects exactly 1 argument, 0 given" +string(58) "stdClass::{closure}() expects exactly 2 arguments, 1 given" +string(47) "variadic() expects at least 1 argument, 0 given" +string(1) "1" +array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) +}