PHP function missing argument error - php

My validate function looks like that
function validate($data, $data2 = 0, $type)
{
...
Function call example
if ($result = validate($lname, 'name') !== true)
response(0, $result, 'lname');
As you see, my validate function has 3 input vars. I'm not using second var - $data2 often, that's why set it to 0 by default. But when I'm calling this function as given example (as far as I know it means $data=$lname, $data2=0, $type='name') getting error message
Missing argument 3 ($type) for validate()
How can I fix that?

Missing argument 3 ($type) for validate() [1]
Always list optional arguments as the last arguments, never before non-optional arguments.
Since PHP doesn't have named parameters1 nor "overloading ala Java", that's the only way:
function validate($data, $type, $data2 = 0) {
}
1 Error with severity E_WARNING until PHP 7.0 (including); Uncaught ArgumentCountError starting with PHP 7.1rfc (and starting with PHP 8.0 as well for internal functionsrfc).
2 before PHP 8.0, see Named Arguments

You should at least set the $type in this line:
function validate($data, $data2 = 0, $type)
at NULL or '' as you can see here:
function validate($data, $data2 = 0, $type = null)
PHP let you to set a value for the parameters, but you can't define a parameter WITHOUT a preset value AFTER parameter(s) which HAVE a preset value. So if you need to always specify the third param, you have to switch the second and the third like this:
function validate($data, $type, $data2 = 0)

From http://php.net/manual/en/functions.arguments.php
Note that when using default arguments, any defaults should be on the right side of any non-default arguments; otherwise, things will not work as expected
Your should switch the second and third arguments of the function, making the optional argument the last one. So it becomes:
function validate($data, $type, $data2 = 0)
{ ....

function validate($data, $data2, $data3, $data4, $data5)
im a beginner but i think that you can use a thousand arguments
as long as you call like that
if ($result = validate($lname, 'name','','','') !== true)

Notice that starting with PHP 7.1 this will throw a PHP Fatal error, not just a warning:
PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function validate(), 2 passed in /path/to/file.php on line X and exactly 3 expected
More info: http://php.net/manual/en/migration71.incompatible.php

Related

TYPO3 V11 : "PHP Warning: Undefined array key" , $this->request->getArguments() is empty

I'm a new user of typo3 and I made a plugin to display users with a searchbar to filter them, but I have this error when I want to display my page :
(1/1) #1476107295 TYPO3\CMS\Core\Error\Exception
PHP Warning: Undefined array key "word" in MyPath/Controller/UserlistController.php line 44
In my controller, I try to get arguments to use it in my filter like this :
public function listAction(int $currentPage = 1)
{
$arguments = $this->request->getArguments();
$users = $this->userlistRepository->findBySearch($arguments['word'] ? $arguments['word'] : '');
somecode ...
}
I tried a dump of $arguments, but it's empty
there is a part of my repository :
/**
* #param string $word
* #return object[]|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
* #throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
*/
public function findBySearch(string $word) {
$query = $this->persistenceManager->createQueryForType(\TYPO3\CMS\Extbase\Domain\Model\FrontendUser::class);
$querySettings = $query->getQuerySettings();
$querySettings->setStoragePageIds([26]);
$query->setQuerySettings($querySettings);
$query->setOrderings([
'lastName' => QueryInterface::ORDER_ASCENDING
]);
Someone know why I can't get arguments ? thanks
If you need more part of code, please tell me
If you just call the List action without sending the filter form the arguments are empty.
You should test each expected argument before accessing it like this:
if($this->request->hasArgument('word')) {
$searchOption = $this->request->getArgument('word'));
}
You could try using the null coalescencing operator here:
$users = $this->userlistRepository->findBySearch($arguments['word'] ?? '');
If that doesn't do the trick, you check if the value is set before (see the answer of Tobias Gaertner). Also keep in mind that
$this->request->getArguments();
only gets the arguments in your current plugin context, so any parameters looking like tx_yourplugin_p1[argument]. You have to make sure you properly pass this parameter. If you have to use the general GET parameters, you can use
\TYPO3\CMS\Core\Utility\GeneralUtility::_GET();
While the handling of the 'word' variable is one issue, I consider that if no search word is sent, perhaps another Repository-Method should be called.
Below I entered $this->userlistRepository->findAll() but it could also show something else, perhaps just a template that states that a choice is required.
public function listAction(int $currentPage = 1)
{
$arguments = $this->request->getArguments();
if($this->request->hasArgument('word')) {
$searchOption = $this->request->getArgument('word');
$users = $this->userlistRepository->findBySearch($searchOption);
}
else {
$users = $this->userlistRepository->findAll();
somecode ...
}
}
I tried all solutions, it turns out the error is coming from my repository, I tried a simple
$users = $this->userlistRepository->findAll();
and I got this error:
HP Warning: Undefined array key "tx_vendor_domain_model_vendor" in /mypath/htdocs/public/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapFactory.php line 224

PHP Fatal error: Cannot use positional argument after argument unpacking

Goal
I would like to write a function with variable number of parameters (using ...) that calls another function with the same arguments and a new one at the end. Order is important! The example below is just for demonstration.
What I tried
function foo(...$params) {
$extraVariable = 6;
var_dump(...$params, $extraVariable);
}
foo(2, 4, 1, 4);
Problem
When I run it, I get the following error message:
PHP Fatal error: Cannot use positional argument after argument unpacking in /home/user/main.php on line 3
How can I achieve my goal?
tl;dr
Unpacking after arguments is not allowed by design, but there are 3 workarounds:
Create an array from the new element and unpack that as Paul suggested:
function foo(...$params) {
$extraVariable = 6;
var_dump(...$params, ...[$extraVariable]);
}
Push the new element to the params:
function foo(...$params) {
$extraVariable = 6;
$params[] = $extraVariable;
var_dump(...$args);
}
If the wrapped function has named params, just add the extra argument as a named one as James suggested:
// needs PHP 8.1
function foo(...$params) {
$extraVariable = true;
array_search(...$params, strict: $extraVariable);
}
Explanation
PHP simply doesn't support this. You can see the unit test that checks this behavior:
--TEST--
Positional arguments cannot be used after argument unpacking
--FILE--
<?php
var_dump(...[1, 2, 3], 4);
?>
--EXPECTF--
Fatal error: Cannot use positional argument after argument unpacking in %s on line %d
There is a workaround. You cannot use positional arguments after unpacked one, but you can use several unpacked arguments; so you can just wrap your variable(s) in array literal and unwrap it like this:
var_dump(...$params, ...[$extraVariable]);
See the bolded word?
PHP Fatal error: Cannot use positional argument after argument unpacking in /home/user/main.php on line 3
So use it before unpacking.
var_dump($extraVariable, ...$params);
This is now possible with PHP 8.1 and named parameters.
function foo(...$params) {
$this->otherfunction($params, otherParam: 'some value');
}
foo(2, 4, 1);
In otherfunction() you'll have the expanded values of $params as an array [0 => 2, 1 => 4, 2 => 1], and your $otherParam will have the value "some value".
Note: You stated:
I would like to write a function with variable number of parameters
(using ...) that calls another function with the same arguments and a
new one at the end
Which the above with named params resolves, but your example uses var_dump(). Spread doesn't work in var_dump() but then you would just dump the array itself as that's what var_dump does.

function simplify argument list

When calling a function is there a way to simplify the argument list? Instead of using $blank.
$subscribe=1;
$database->information($blank,$blank,$blank,$blank,$blank,$blank,$subscribe,$blank,$blank,$blank,$blank,$blank);
function information ($search,$id,$blank,$category,$recent,$comment,$subscribe,$pages,$pending,$profile,$deleted,$reported) {
//code
}
You could pass in an array with the specified keys, and merge it with an array of default values
So instead of
function foo($arg1 = 3, $arg2 = 5, $arg3 = 7) { }
You'd have
function foo($args) {
$defaults = array(
'arg1' => '',
'arg2' => null,
'arg3' => 7
);
// merge passed in array with defaults
$args = array_merge($defaults, $args);
// set variables within local scope
foreach($args as $key => $arg) {
// this is to make sure that only intended arguments are passed
if(isset($defaults[$key])) ${$key} = $arg;
}
// rest of your code
}
Then call it as
foo(array('arg3' => 2));
Yes, pass an array instead, or refactor. A long arguments list is usually a bad smell.
function information(array $params) {....
information(array('search'=>'.....
Twelve arguments are generally too many for one function. It's likely that your code could be simplified (including the argument lists getting shorter) by refactoring function information which looks likely to be a monster.
Stopgap measures you can use in the meantime are
adding default argument values
making the function accept all its arguments as an array
Both of the above will require you to visit all call sites for the function for review and modification.
Adding default arguments is IMHO the poor choice here, as by looking at the example call it seems that you would need to make all arguments default, which in turn means that the compiler will never warn you if you call the function wrongly by mistake.
Converting to an array is more work, but it forces you to rewrite the calls in a way that's not as amenable to accidental errors. The function signature would change to
function information(array $params)
or possibly
function information(array $params = array())
if you want all parameters to be optional. You can supply defaults for the parameters with
function information(array $params) {
$defaults = array('foo' => 'bar', /* ... */);
$params += $defaults; // adds missing values that have defaults to $params;
// does not overwrite existing values
To avoid having to rewrite the function body, you can then use export to pull out these values from the array into the local scope:
export($params); // creates local vars
echo $foo; // will print "bar" unless you have given another value
See all of this in action.
You can make it so the function wil automatically fill the variable with a given value like an empty string:
function information ($subscribe, $search="", $id="", $blank="", $category="", $recent="", $comment="", $pages="", $pending="", $profile="", $deleted="", $reported="") {
//code
}
Yes, there are several ways:
Accept an associative array as a single argument, and pass what you need to that. Throw exceptions if a critical argument is missing.
Place critical arguments at the head of the function definition, and optional ones at the end. Give them a default value so that you don't have to declare them.
Recosinder your function. 12 arguments is much too many for one function. Consider using a class/object, or dividing the work between different functions.
Several ways:
function test($input = "some default value") {
return $input; // returns "some default value"
}
function test($input) {
return $input;
}
test(NULL); // returns NULL
function test() {
foreach(func_get_args() as $arg) {
echo $arg;
}
}
test("one", "two", "three"); // echos: onetwothree

PHP Function with Optional Parameters

I've written a PHP function that can accept 10 parameters, but only 2 are required. Sometimes, I want to define the eighth parameter, but I don't want to type in empty strings for each of the parameters until I reach the eighth.
One idea I had was to pass an abstracted function with an array of parameters which passes it along to the real function.
Is there a better way to set up the function so I can pass in only the parameters I want?
What I have done in this case is pass an array, where the key is the parameter name, and the value is the value.
$optional = array(
"param" => $param1,
"param2" => $param2
);
function func($required, $requiredTwo, $optional) {
if(isset($optional["param2"])) {
doWork();
}
}
Make the function take one parameter: an array. Pass in the actual parameters as values in the array.
Edit: the link in Pekka's comment just about sums it up.
To accomplish what you want, use an array Like Rabbot said (though this can become a pain to document/maintain if used excessively). Or just use the traditional optional args.
//My function with tons of optional params
function my_func($req_a, $req_b, $opt_a = NULL, $opt_b = NULL, $opt_c = NULL)
{
//Do stuff
}
my_func('Hi', 'World', null, null, 'Red');
However, I usually find that when I start writing a function/method with that many arguments - more often than not it is a code smell, and can be re-factored/abstracted into something much cleaner.
//Specialization of my_func - assuming my_func itself cannot be refactored
function my_color_func($reg_a, $reg_b, $opt = 'Red')
{
return my_func($reg_a, $reg_b, null, null, $opt);
}
my_color_func('Hi', 'World');
my_color_func('Hello', 'Universe', 'Green');
You can just set the default value to null.
<?php
function functionName($value, $value2 = null) {
// do stuff
}
In PHP 5.6 and later, argument lists may include the ... token to denote that the function accepts a variable number of arguments. The arguments will be passed into the given variable as an array; for example:
Example Using ... to access variable arguments
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
The above example will output:
10
Variable-length argument lists PHP Documentation
NOTE: This is an old answer, for PHP 5.5 and below. PHP 5.6+ supports default arguments
In PHP 5.5 and below, you can achieve this by using one of these 2 methods:
using the func_num_args() and func_get_arg() functions;
using NULL arguments;
How to use
function method_1()
{
$arg1 = (func_num_args() >= 1)? func_get_arg(0): "default_value_for_arg1";
$arg2 = (func_num_args() >= 2)? func_get_arg(1): "default_value_for_arg2";
}
function method_2($arg1 = null, $arg2 = null)
{
$arg1 = $arg1? $arg1: "default_value_for_arg1";
$arg2 = $arg2? $arg2: "default_value_for_arg2";
}
I prefer the second method because it's clean and easy to understand, but sometimes you may need the first method.
Starting with PHP 8 you are able to use named arguments:
function namedParameters($paramOne, $paramTwo, $paramThree = 'test', $paramFour = null)
{
dd($paramOne, $paramTwo, $paramThree, $paramFour);
}
We can now call this function with the required params and only the optinal params, that we want to differ from the default value which we specified in the function.
namedParameters('one', 'two', paramFour: 'four');
Result:
// "one", "two", "test", "four"
I think, you can use objects as params-transportes, too.
$myParam = new stdClass();
$myParam->optParam2 = 'something';
$myParam->optParam8 = 3;
theFunction($myParam);
function theFunction($fparam){
return "I got ".$fparam->optParam8." of ".$fparam->optParam2." received!";
}
Of course, you have to set default values for "optParam8" and "optParam2" in this function, in other case you will get "Notice: Undefined property: stdClass::$optParam2"
If using arrays as function parameters, I like this way to set default values:
function theFunction($fparam){
$default = array(
'opt1' => 'nothing',
'opt2' => 1
);
if(is_array($fparam)){
$fparam = array_merge($default, $fparam);
}else{
$fparam = $default;
}
//now, the default values are overwritten by these passed by $fparam
return "I received ".$fparam['opt1']." and ".$fparam['opt2']."!";
}
If only two values are required to create the object with a valid state, you could simply remove all the other optional arguments and provide setters for them (unless you dont want them to changed at runtime). Then just instantiate the object with the two required arguments and set the others as needed through the setter.
Further reading
Martin Fowler on Constructor vs Setter Injection and
Dependency injection through constructors or property setters?
I know this is an old post, but i was having a problem like the OP and this is what i came up with.
Example of array you could pass. You could re order this if a particular order was required, but for this question this will do what is asked.
$argument_set = array (8 => 'lots', 5 => 'of', 1 => 'data', 2 => 'here');
This is manageable, easy to read and the data extraction points can be added and removed at a moments notice anywhere in coding and still avoid a massive rewrite. I used integer keys to tally with the OP original question but string keys could be used just as easily. In fact for readability I would advise it.
Stick this in an external file for ease
function unknown_number_arguments($argument_set) {
foreach ($argument_set as $key => $value) {
# create a switch with all the cases you need. as you loop the array
# keys only your submitted $keys values will be found with the switch.
switch ($key) {
case 1:
# do stuff with $value
break;
case 2:
# do stuff with $value;
break;
case 3:
# key 3 omitted, this wont execute
break;
case 5:
# do stuff with $value;
break;
case 8:
# do stuff with $value;
break;
default:
# no match from the array, do error logging?
break;
}
}
return;
}
put this at the start if the file.
$argument_set = array();
Just use these to assign the next piece of data use numbering/naming according to where the data is coming from.
$argument_set[1][] = $some_variable;
And finally pass the array
unknown_number_arguments($argument_set);
function yourFunction($var1, $var2, $optional = Null){
... code
}
You can make a regular function and then add your optional variables by giving them a default Null value.
A Null is still a value, if you don't call the function with a value for that variable, it won't be empty so no error.
As of PHP 7.1.0, type declarations can be marked nullable by prefixing the type name with a question mark (?). This signifies that the value can be of the specified type or null
<?php
function name(?string $varname){
echo is_null($varname);
}
name();
name('hey');
?>
for more info: Click here
If you are commonly just passing in the 8th value, you can reorder your parameters so it is first. You only need to specify parameters up until the last one you want to set.
If you are using different values, you have 2 options.
One would be to create a set of wrapper functions that take different parameters and set the defaults on the others. This is useful if you only use a few combinations, but can get very messy quickly.
The other option is to pass an array where the keys are the names of the parameters. You can then just check if there is a value in the array with a key, and if not use the default. But again, this can get messy and add a lot of extra code if you have a lot of parameters.
PHP allows default arguments (link). In your case, you could define all the parameters from 3 to 8 as NULL or as an empty string "" depending on your function code. In this way, you can call the function only using the first two parameters.
For example:
<?php
function yourFunction($arg1, $arg2, $arg3=NULL, $arg4=NULL, $arg5=NULL, $arg6=NULL, $arg7=NULL, $arg8=NULL){
echo $arg1;
echo $arg2;
if(isset($arg3)){echo $arg3;}
# other similar statements for $arg4, ...., $arg5
if(isset($arg8)){echo $arg8;}
}
Just set Null to ignore parameters that you don't want to use and then set the parameter needed according to the position.
function myFunc($p1,$p2,$p3=Null,$p4=Null,$p5=Null,$p6=Null,$p7=Null,$p8=Null){
for ($i=1; $i<9; $i++){
$varName = "p$i";
if (isset($$varName)){
echo $varName." = ".$$varName."<br>\n";
}
}
}
myFunc( "1", "2", Null, Null, Null, Null, Null, "eight" );
func( "1", "2", default, default, default, default, default, "eight" );

How to pass specific variable in PHP function

I have a PHP function that requires can take 3 parameteres... I want to pass it a value for the 1st and 3rd parameters but I want the 2nd one to default...
How can I specify which ones I am passing, otherwise its interpreted as me passing values for the 1st and 2nd slots.
Thanks.
You cannot "not pass" a parameter that's not at the end of the parameters list :
if you want to specify the 3rd parameter, you have to pass the 1st and 2nd ones
if you want to specify the 2nd parameter, you have to pass the 1st one -- but the 3rd can be left out, if optionnal.
In your case, you have to pass a value for the 2nd parameter -- the default one, ideally ; which, yes, requires your to know that default value.
A possible alternative would be not have your function take 3 parameters, but only one, an array :
function my_function(array $params = array()) {
// if set, use $params['first']
// if set, use $params['third']
// ...
}
And call that function like this :
my_function(array(
'first' => 'plop',
'third' => 'glop'
));
This would allow you to :
accept any number of parameters
all of which could be optionnal
But :
your code would be less easy to understand, and the documentation would be less useful : no named parameters
your IDE would not be able to give you hints on which parameters the function accepts
Once you've defined a default parameter, all the parameters after that one cannot be required. You could do something like:
const MY_FUNCTION_DEFAULT = "default";
public function myFunction($one, $two = "default", $three = 3)
{
if (is_null($two)) $two = self::MY_FUNCTION_DEFAULT;
//...
}
// call
$this->myFunction(1, null, 3);
You might also define an empty parameter set and use func_get_args to pull in parameters and analyze those using instanceof or typeof/gettype for type checking if your function is simple enough.
You could use ReflectionFunction. This problem has already been solved by an anonymous contributor at php.net, see orinal here: http://www.php.net/manual/en/function.call-user-func-array.php#66121
For those wishing to implement call-by-name functionality in PHP, such as implemented e.g. in DB apis, here's a quick-n-dirty version for PHP 5 and up
function call_user_func_named($function, $params)
{
// make sure we do not throw exception if function not found: raise error instead...
// (oh boy, we do like php 4 better than 5, don't we...)
if (!function_exists($function))
{
trigger_error('call to unexisting function '.$function, E_USER_ERROR);
return NULL;
}
$reflect = new ReflectionFunction($function);
$real_params = array();
foreach ($reflect->getParameters() as $i => $param)
{
$pname = $param->getName();
if ($param->isPassedByReference())
{
/// #todo shall we raise some warning?
}
if (array_key_exists($pname, $params))
{
$real_params[] = $params[$pname];
}
else if ($param->isDefaultValueAvailable()) {
$real_params[] = $param->getDefaultValue();
}
else
{
// missing required parameter: mark an error and exit
//return new Exception('call to '.$function.' missing parameter nr. '.$i+1);
trigger_error(sprintf('call to %s missing parameter nr. %d', $function, $i+1), E_USER_ERROR);
return NULL;
}
}
return call_user_func_array($function, $real_params);
}
function ($foo, $mate, $bar = "") {
// ... some code
}

Categories