Unfortunately, if you need to use an optional parameter at the very end of the parameter list, you have to specify everything up until that last parameter. Generally if you want to mix-and-match, you give them default values of '' or null, and don't use them inside the function if they are that default value.
Which, as eloquently said in the comments, is using arrays to emulate named arguments.
This gives ultimate flexibility but may not be needed in some cases. At the very least you can move whatever you think is not expected most of the time to the end of the argument list.
Nope, it's not possible to skip arguments this way. You can omit passing arguments only if they are at the end of the parameter list.
There was an official proposal for this: https://wiki.php.net/rfc/skipparams, which got declined. The proposal page links to other SO questions on this topic.
As mentioned above, you will not be able to skip parameters. I've written this answer to provide some addendum, which was too large to place in a comment.
@Frank Nocke proposes to call the function with its default parameters, so for example having
function a($b=0, $c=NULL, $d=''){ //...
you should use
$var = a(0, NULL, 'ddd');
which will functionally be the same as omitting the first two ($b and $c) parameters.
It is not clear which ones are defaults (is 0 typed to provide default value, or is it important?).
There is also a danger that default values problem is connected to external (or built-in) function, when the default values could be changed by function (or method) author. So if you wouldn't change your call in the program, you could unintentionally change its behaviour.
Some workaround could be to define some global constants, like DEFAULT_A_B which would be "default value of B parameter of function A" and "omit" parameters this way:
$var = a(DEFAULT_A_B, DEFAULT_A_C, 'ddd');
For classes it is easier and more elegant if you define class constants, because they are part of global scope, eg.
class MyObjectClass {
const DEFAULT_A_B = 0;
function a($b = self::DEFAULT_A_B){
// method body
}
}
$obj = new MyObjectClass();
$var = $obj->a(MyObjectClass::DEFAULT_A_B); //etc.
Note that this default constant is defined exactly once throughout the code (there is no value even in method declaration), so in case of some unexpected changes, you will always supply the function/method with correct default value.
The clarity of this solution is of course better than supplying raw default values (like NULL, 0 etc.) which say nothing to a reader.
(I agree that calling like $var = a(,,'ddd'); would be the best option)
So basically with debug_backtrace() I get the function name in which this code is placed, to then create a new ReflectionFunction object and loop though all function arguments.
In the loop I simply check if the function argument is empty() AND the argument is "optional" (means it has a default value). If yes I simply assign the default value to the argument.
Nothing has changed regarding being able to skip optional arguments, however for correct syntax and to be able to specify NULL for arguments that I want to skip, here's how I'd do it:
define('DEFAULT_DATA_LIMIT', '50');
define('DEFAULT_DATA_PAGE', '1');
/**
* getData
* get a page of data
*
* Parameters:
* name - (required) the name of data to obtain
* limit - (optional) send NULL to get the default limit: 50
* page - (optional) send NULL to get the default page: 1
* Returns:
* a page of data as an array
*/
function getData($name, $limit = NULL, $page = NULL) {
$limit = ($limit===NULL) ? DEFAULT_DATA_LIMIT : $limit;
$page = ($page===NULL) ? DEFAULT_DATA_PAGE : $page;
...
}
This can the be called thusly: getData('some name',NULL,'23'); and anyone calling the function in future need not remember the defaults every time or the constant declared for them.
As advised earlier, nothing changed.
Beware, though, too many parameters (especially optional ones) is a strong indicator of code smell.
Perhaps your function is doing too much:
// first build context
$dataFetcher->setPage(1);
// $dataFetcher->setPageSize(50); // not used here
// then do the job
$dataFetcher->getData('some name');
Some parameters could be grouped logically:
$pagination = new Pagination(1 /*, 50*/);
getData('some name', $pagination);
// Java coders will probably be familiar with this form:
getData('some name', new Pagination(1));
In last resort, you can always introduce an ad-hoc parameter object:
$param = new GetDataParameter();
$param->setPage(1);
// $param->setPageSize(50); // not used here
getData($param);
Sometimes, the very reason for making a parameter optional is wrong. In this example, is $page really meant to be optional? Does saving a couple of characters really make a difference?
// dubious
// it is not obvious at first sight that a parameterless call to "getData()"
// returns only one page of data
function getData($page = 1);
// this makes more sense
function log($message, $timestamp = null /* current time by default */);
As @IbrahimLawal pointed out. It's best practice to just set them to null values. Just check if the value passed is null in which you use your defined defaults.
The simple answer is No. But why skip when re-arranging the arguments achieves this?
Yours is an "Incorrect usage of default function arguments" and will not work as you expect it to.
A side note from the PHP documentation:
When using default arguments, any defaults should be on the right side of any non-default arguments; otherwise, things will not work as expected.
Consider the following:
function getData($name, $limit = '50', $page = '1') {
return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}
echo getData('some name', '', '23'); // won't work as expected
The output will be:
"Select * FROM books WHERE name = some name AND page = 23 limit"
The Correct usage of default function arguments should be like this:
function getData($name, $page = '1', $limit = '50') {
return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}
echo getData('some name', '23'); // works as expected
The output will be:
"Select * FROM books WHERE name = some name AND page = 23 limit 50"
Putting the default on your right after the non-defaults makes sure that it will always retun the default value for that variable if its not defined/given
Here is a link for reference and where those examples came from.
Edit: Setting it to null as others are suggesting might work and is another alternative, but may not suite what you want. It will always set the default to null if it isn't defined.
This is kind of an old question with a number of technically competent answers, but it cries out for one of the modern design patterns in PHP: Object-Oriented Programming. Instead of injecting a collection of primitive scalar data types, consider using an "injected-object" that contains all of the data needed by the function.
http://php.net/manual/en/language.types.intro.php
The injected-object may have property validation routines, etc. If the instantiation and injection of data into the injected-object is unable to pass all of the validation, the code can throw an exception immediately and the application can avoid the awkward process of dealing with potentially incomplete data.
We can type-hint the injected-object to catch mistakes before deployment. Some of the ideas are summarized in this article from a few years ago.
As of PHP 8.0.0, declaring mandatory arguments after optional arguments is deprecated.
You can now omit optional parameters.
Example:
<?php
function foo ( $a = '1', $b = '2', $c = '3' ){
return "A is " . $a . ", B is " . $b . ", C is " . $b
}
echo foo(c: '5');
// Output A is 1, B is 2, C is 5