Function call missing argument [duplicate] - php

This question already has answers here:
Does PHP allow named parameters so that optional arguments can be omitted from function calls?
(17 answers)
Closed 2 years ago.
function fu($arg1 = null, $arg2 = null, $arg3 = null, $arg4 = null){
echo 'helo world';
}
//can be other defaults instead null;
fu('arg1');
fu(,,'arg3');
fu(,'arg2',,'arg4');
how can I call fu if any arguments possibly can be missed?
I can't use fu(null,'arg2',null,'arg4');
because default for arg1, arg3 can contein inf

You have a few options to handle this case. Here the 2 I can think about.
Using an array
With an array you don't bother with how many arguments your function receives, and each argument is named (with the key in the array)
function fu($param = array()) {
// you can test here is $param['arg1'] exists, $param['arg2'] and so on
echo 'helo world';
}
Using func_get_args
This way you can how many arguments you like to the function, but they aren't named
function fu()
{
foreach (func_get_args() as $index => $value) {
echo "Argument {$index} is: \n", var_export($value);
}
}

Just put '' in place of missed arguments for function call.
fu('','','arg3','arg4');

You probably coming from another programming language like Python, but in PHP you cannot skip an intermediate argument like this. The optional parameters should be last. However you can pass a named array to achieve what you want. Something like this:
function fu ($arr =[]) {
foreach ( [1, 2, 3, 4] as $key )
$arr ["arg$key"] =isset($arr["arg$key"]) ? $arr["arg$key"] : null;
print_r ($arr) ;
echo "<br />";
}
fu (['arg1' => 'arg1']) ;
fu (['arg3' => 'arg3']) ;
fu (['arg2' => 'arg2', 'arg4' => 'arg4']) ;

another possible solution, expanding the array approach:
function fu($inputArgs = array()) {
$defaultArgs = array('arg1' => 'x', 'arg2' => 'y');
$args = array_merge ($defaultArgs, $inputArgs);
//either use $args['arg1'] or extract the values:
extract($args);
// now you can use $arg1, $arg2... directly
...
}
you can enter a non-default value by using the same key in the $inputArgs array, for example :
fu(array('arg2' => 'z'));

You can use func_get_arg() if your arguments are not fixed.
function fu(){
$args = func_get_args();
print_r($args);
}
Now you can pass anything like fu() or fu('1','null',null) or fu(null,'arg2',null,'arg4'); etc.

Languages such as Java offer multiple variations of the same method to overcome this but in PHP only one variation is possible.
For arguments that will not be used you will have to use the default argument values as arguments.
fu('arg1');
fu(null, null, 'arg3');
fu(null, 'arg2', null, 'arg4');
My advice on methods with too many optional arguments is either your code is too complicated and may profit from a refactoring such as creating a class and passing the arguments to setters or if you want to implement a function with no preset amount of arguments, it would probably make sense to use func_get_args();

Related

What's the best way to read parameters of a function in php?

In the past few years I've used this formula to read parameters in my methods inside my php classes:
$params = func_get_args();
if(is_array($params[0])){
foreach($params[0] as $key => $value){
${$key} = $value;
}
}
And it works fine, as if I pass something like this:
$class->foo(array('bar' => 'hello', 'planet' => 'world'));
I will have in my foo method the variables bar and planet with their relative values.
But what I'm asking is: Is there any better way to do it? Something that maybe I can encapsulate in another method for example?
UPDATE
So, taking in consideration rizier123 comment, and after a chat with a friend of mine, I nailed down what I think is the better way pass parameters to function. As I know that I will always pass just one parameter to the function, which is always going to be an array, there's no need to call the func_get_args() function, but I better to expect an array all the time and by default I set an empty array, like in the following example:
class MyClass{
public function MyMethod(array $options = array()){
extract($options);
}
}
$my = new MyClass();
$my->MyMethod(array('name' => 'john', 'surname' => 'doe'));
// Now MyMethod has two internal vars called $name and $surname
Yes you can use extract() to convert your arrays to variables, like this:
extract($params[0]);
There is a new feature from PHP 5.6, it's called Variadic functions
http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
function foo(...$arguments) {
foreach ($arguments as $arg) {
var_dump($arg);
}
}
foo('1', 2, true, new DateTime('now'));
You can do this with PHP built-in function extract().
Use it this way:
$var_array = array("color" => "blue",
"size" => "medium",
"shape" => "sphere");
extract($var_array);
When you run echo $color, $size, $shape; it outputs:
blue, medium, sphere

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 - Inherit function default value

I have a function that look like this:
function test($arg1 = 'my_value', $arg2 = 'second')
{
}
When I call it I only want to set the second value to something different, like this:
test(inherit, 'changed value');
I found out that it is possible to add this line to my function (when my "inherit" is changed to null):
$arg1 = ( is_null( $arg1 ) ? 'my_value' : $arg1 );
Is there a better way, a nicer way to solve it?
Depending on the nature and number of your parameters it may be reasonable to use named parameters (at least emulated):
function xyz($args) {
$args += array(
'x' => 'default',
'q' => 'default 2',
// ...
);
// ...
}
xyz(array('q' => 'hehe, not default'));
The way you have solved it is actually pretty usable.
The other way is to pass the same value as the default value every time on the function call.
If that is structural, then you have to reconsider the function.
Make two different functions:
// Full function
function testex($arg1 = 'my_value', $arg2 = 'second')
{
}
// Shorthand when just argument 2 is needed
function test2($arg2 = 'second')
{
return testex('my_value', $arg2);
}
That way, you don't have to pass null to the first parameter when you don't need to.
You will have to flip them, you can't leave the first value to be blank,
Set the first value and let the second one be the default value;
UPDATE:
If you want to have dynamic length to your argument consider using the func_get_args();
function something() {
$args = func_get_args();
....
}
then you can test your arguments for different value or datatype to make them do whatever yuo please

PHP Optional Parameters - specify parameter value by name?

I know it is possible to use optional arguments as follows:
function doSomething($do, $something = "something") {
}
doSomething("do");
doSomething("do", "nothing");
But suppose you have the following situation:
function doSomething($do, $something = "something", $or = "or", $nothing = "nothing") {
}
doSomething("do", $or=>"and", $nothing=>"something");
So in the above line it would default $something to "something", even though I am setting values for everything else. I know this is possible in .net - I use it all the time. But I need to do this in PHP if possible.
Can anyone tell me if this is possible? I am altering the Omnistar Affiliate program which I have integrated into Interspire Shopping Cart - so I want to keep a function working as normal for any places where I dont change the call to the function, but in one place (which I am extending) I want to specify additional parameters. I dont want to create another function unless I absolutely have to.
No, in PHP that is not possible as of writing. Use array arguments:
function doSomething($arguments = array()) {
// set defaults
$arguments = array_merge(array(
"argument" => "default value",
), $arguments);
var_dump($arguments);
}
Example usage:
doSomething(); // with all defaults, or:
doSomething(array("argument" => "other value"));
When changing an existing method:
//function doSomething($bar, $baz) {
function doSomething($bar, $baz, $arguments = array()) {
// $bar and $baz remain in place, old code works
}
Have a look at func_get_args: http://au2.php.net/manual/en/function.func-get-args.php
Named arguments are not currently available in PHP (5.3).
To get around this, you commonly see a function receiving an argument array() and then using extract() to use the supplied arguments in local variables or array_merge() to default them.
Your original example would look something like:
$args = array('do' => 'do', 'or' => 'not', 'nothing' => 'something');
doSomething($args);
PHP has no named parameters. You'll have to decide on one workaround.
Most commonly an array parameter is used. But another clever method is using URL parameters, if you only need literal values:
function with_options($any) {
parse_str($any); // or extract() for array params
}
with_options("param=123&and=and&or=or");
Combine this approach with default parameters as it suits your particular use case.

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" );

Categories