PHP function - ignore some default parameters [duplicate] - php

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Any way to specify optional parameter values in PHP?
just randomly came across this.
If I have a function like so:
public function getSomething($orderBy='x', $direction = 'DESC', $limit=null){
//do something random
}
When calling the function is it possible to ignore the first two fields and leave them default yet specify the 3rd.
For example:
$random = $this->my_model->getSomething(USE_DEFAULT, USE_DEFAULT, 10);
I know I can pass the 1st and 2nd parameters but all im asking is if their is some kind of special keyword that just says use the default value.
Hope that makes sense. its not a problem, just curious.
thanks for reading

You need to do that yourself. You can use null to indicate that a default value should be used:
public function getSomething($orderBy = null, $direction = null, $limit = null) {
// fallbacks
if ($orderBy === null) $orderBy = 'x';
if ($direction === null) $direction = 'DESC';
// do something random
}
Then pass null when calling it to indicate that you want to use the defaults:
$random = $this->my_model->getSomething(null, null, 10);
Another possible solution that I use sometimes is an additional parameter at the very end of the parameter list, containing all optional parameters:
public function foo($options = array()) {
// merge with defaults
$options = array_merge(array(
'orderBy' => 'x',
'direction' => 'DESC',
'limit' => null
), $options);
// do stuff
}
That way you do not need to specify all optional arguments. array_merge() ensures that you are always dealing with a complete set of options. You would use it like this:
$random = $this->my_model->foo(array('limit' => 10));
It seems like there is no required parameter this particular case, but if you need one, simply add it in front of the optional ones:
public function foo($someRequiredParameter, $someOtherRequiredParameter, $options = array()) {
// ...
}

Honestly, this becomes a problem when functions are trying to do too much. There's almost always a better design pattern when you see a function grow to more than a few parameters (usually it's the poor guy that inherited the old code, and appending parameters is this quickest way to "get the job done").
Elusive's answer is the best according to your question, but take a look at cyclomatic complexity:
http://en.wikipedia.org/wiki/Cyclomatic_complexity
This is a good way to know if your function is doing too much, which makes your question less of a problem than it probably is now.

I don't think PHP can do this. The best solution that I know of is outlined here:
http://www.php.net/manual/en/functions.arguments.php#70511

You cannot ignore params. But you can do something Like this:
public function getSomething($limit=null){
return $this->getSomething('x','DESC',$limit);
}
public function getSomething($orderBy='x', $direction = 'DESC', $limit=null){
...
}
see ya

Related

Should I pass all values if there are many optional parameters in PHP [duplicate]

OK I totally forgot how to skip arguments in PHP.
Lets say I have:
function getData($name, $limit = '50', $page = '1') {
...
}
How would I call this function so that the middle parameter takes the default value (ie. '50')?
getData('some name', '', '23');
Would the above be correct? I can't seem to get this to work.
Your post is correct.
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.
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.
There's no way to "skip" an argument other than to specify a default like false or null.
Since PHP lacks some syntactic sugar when it comes to this, you will often see something like this:
checkbox_field(array(
'name' => 'some name',
....
));
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.
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.
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 feature is implemented in PHP 8.0
PHP 8 introduced named arguments
which:
allows skipping default values arbitrarily
The documentation for reference
No changes necessary to use this feature:
lets use OPs function function getData($name, $limit = '50', $page = '1')
Usage
getData(name: 'some name', page: '23');
Native functions will also use this feature
htmlspecialchars($string, double_encode: false);
// Same as
htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);
Netbeans IDE 12.3 Feature Supported
This feature is supported, with the exception of code completion for named arguments, looks better ;)
For any parameter skipped (you have to) go with the default parameter, to be on the safe side.
(Settling for null where the default parameter is '' or similar or vice versa will get you into troublew...)
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)
You can't skip arguments but you can use array parameters and you need to define only 1 parameter, which is an array of parameters.
function myfunction($array_param)
{
echo $array_param['name'];
echo $array_param['age'];
.............
}
And you can add as many parameters you need, you don't need to define them. When you call the function, you put your parameters like this:
myfunction(array("name" => "Bob","age" => "18", .........));
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.
https://www.experts-exchange.com/articles/18409/Using-Named-Parameters-in-PHP-Function-Calls.html
I had to make a Factory with optional parameters, my workaround was to use the null coalescing operator:
public static function make(
string $first_name = null,
string $last_name = null,
string $email = null,
string $subject = null,
string $message = null
) {
$first_name = $first_name ?? 'First';
$last_name = $last_name ?? 'Last';
$email = $email ?? 'foo#bar.com';
$subject = $subject ?? 'Some subject';
$message = $message ?? 'Some message';
}
Usage:
$factory1 = Factory::make('First Name Override');
$factory2 = Factory::make(null, 'Last Name Override');
$factory3 = Factory::make(null, null, null, null 'Message Override');
Not the prettiest thing, but might be a good pattern to use in Factories for tests.
Well as everyone else already said, that what you want won't be possible in PHP without adding any code lines in the function.
But you can place this piece of code at the top of a function to get your functionality:
foreach((new ReflectionFunction(debug_backtrace()[0]["function"]))->getParameters() as $param) {
if(empty(${$param->getName()}) && $param->isOptional())
${$param->getName()} = $param->getDefaultValue();
}
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.
Demo
Set the limit to null
function getData($name, $limit = null, $page = '1') {
...
}
and call to that function
getData('some name', null, '23');
if you want to set the limit you can pass as an argument
getData('some name', 50, '23');
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);
(which is just a glorified version of the less formal parameter array technique)
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 */);
This snippet:
function getData($name, $options) {
$default = array(
'limit' => 50,
'page' => 2,
);
$args = array_merge($default, $options);
print_r($args);
}
getData('foo', array());
getData('foo', array('limit'=>2));
getData('foo', array('limit'=>10, 'page'=>10));
Answer is :
Array
(
[limit] => 50
[page] => 2
)
Array
(
[limit] => 2
[page] => 2
)
Array
(
[limit] => 10
[page] => 10
)
This is what I would do:
<?php
function getData($name, $limit = '', $page = '1') {
$limit = (EMPTY($limit)) ? 50 : $limit;
$output = "name=$name&limit=$limit&page=$page";
return $output;
}
echo getData('table');
/* output name=table&limit=50&page=1 */
echo getData('table',20);
/* name=table&limit=20&page=1 */
echo getData('table','',5);
/* output name=table&limit=50&page=5 */
function getData2($name, $limit = NULL, $page = '1') {
$limit = (ISSET($limit)) ? $limit : 50;
$output = "name=$name&limit=$limit&page=$page";
return $output;
}
echo getData2('table');
// /* output name=table&limit=50&page=1 */
echo getData2('table',20);
/* output name=table&limit=20&page=1 */
echo getData2('table',NULL,3);
/* output name=table&limit=50&page=3 */
?>
Hope this will help someone
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
Try This.
function getData($name, $limit = NULL, $page = '1') {
if (!$limit){
$limit = 50;
}
}
getData('some name', '', '23');
You can not skip middle parameter in your function call. But, you can work around with this:
function_call('1', '2', '3'); // Pass with parameter.
function_call('1', null, '3'); // Pass without parameter.
Function:
function function_call($a, $b='50', $c){
if(isset($b)){
echo $b;
}
else{
echo '50';
}
}
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.
<?php
define('DEFAULT_LIMIT', 50);
define('DEFAULT_PAGE', 1);
function getData($name, $limit = null, $page = null) {
$limit = is_null($limit) ? DEFAULT_LIMIT : $limit;
$page = is_null($page) ? DEFAULT_PAGE : $page;
...
}
?>
Hope this helps.
getData('some name');
just do not pass them and the default value will be accepted

Can we use argument placeholders when calling php functions? [duplicate]

OK I totally forgot how to skip arguments in PHP.
Lets say I have:
function getData($name, $limit = '50', $page = '1') {
...
}
How would I call this function so that the middle parameter takes the default value (ie. '50')?
getData('some name', '', '23');
Would the above be correct? I can't seem to get this to work.
Your post is correct.
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.
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.
There's no way to "skip" an argument other than to specify a default like false or null.
Since PHP lacks some syntactic sugar when it comes to this, you will often see something like this:
checkbox_field(array(
'name' => 'some name',
....
));
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.
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.
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 feature is implemented in PHP 8.0
PHP 8 introduced named arguments
which:
allows skipping default values arbitrarily
The documentation for reference
No changes necessary to use this feature:
lets use OPs function function getData($name, $limit = '50', $page = '1')
Usage
getData(name: 'some name', page: '23');
Native functions will also use this feature
htmlspecialchars($string, double_encode: false);
// Same as
htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);
Netbeans IDE 12.3 Feature Supported
This feature is supported, with the exception of code completion for named arguments, looks better ;)
For any parameter skipped (you have to) go with the default parameter, to be on the safe side.
(Settling for null where the default parameter is '' or similar or vice versa will get you into troublew...)
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)
You can't skip arguments but you can use array parameters and you need to define only 1 parameter, which is an array of parameters.
function myfunction($array_param)
{
echo $array_param['name'];
echo $array_param['age'];
.............
}
And you can add as many parameters you need, you don't need to define them. When you call the function, you put your parameters like this:
myfunction(array("name" => "Bob","age" => "18", .........));
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.
https://www.experts-exchange.com/articles/18409/Using-Named-Parameters-in-PHP-Function-Calls.html
I had to make a Factory with optional parameters, my workaround was to use the null coalescing operator:
public static function make(
string $first_name = null,
string $last_name = null,
string $email = null,
string $subject = null,
string $message = null
) {
$first_name = $first_name ?? 'First';
$last_name = $last_name ?? 'Last';
$email = $email ?? 'foo#bar.com';
$subject = $subject ?? 'Some subject';
$message = $message ?? 'Some message';
}
Usage:
$factory1 = Factory::make('First Name Override');
$factory2 = Factory::make(null, 'Last Name Override');
$factory3 = Factory::make(null, null, null, null 'Message Override');
Not the prettiest thing, but might be a good pattern to use in Factories for tests.
Well as everyone else already said, that what you want won't be possible in PHP without adding any code lines in the function.
But you can place this piece of code at the top of a function to get your functionality:
foreach((new ReflectionFunction(debug_backtrace()[0]["function"]))->getParameters() as $param) {
if(empty(${$param->getName()}) && $param->isOptional())
${$param->getName()} = $param->getDefaultValue();
}
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.
Demo
Set the limit to null
function getData($name, $limit = null, $page = '1') {
...
}
and call to that function
getData('some name', null, '23');
if you want to set the limit you can pass as an argument
getData('some name', 50, '23');
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);
(which is just a glorified version of the less formal parameter array technique)
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 */);
This snippet:
function getData($name, $options) {
$default = array(
'limit' => 50,
'page' => 2,
);
$args = array_merge($default, $options);
print_r($args);
}
getData('foo', array());
getData('foo', array('limit'=>2));
getData('foo', array('limit'=>10, 'page'=>10));
Answer is :
Array
(
[limit] => 50
[page] => 2
)
Array
(
[limit] => 2
[page] => 2
)
Array
(
[limit] => 10
[page] => 10
)
This is what I would do:
<?php
function getData($name, $limit = '', $page = '1') {
$limit = (EMPTY($limit)) ? 50 : $limit;
$output = "name=$name&limit=$limit&page=$page";
return $output;
}
echo getData('table');
/* output name=table&limit=50&page=1 */
echo getData('table',20);
/* name=table&limit=20&page=1 */
echo getData('table','',5);
/* output name=table&limit=50&page=5 */
function getData2($name, $limit = NULL, $page = '1') {
$limit = (ISSET($limit)) ? $limit : 50;
$output = "name=$name&limit=$limit&page=$page";
return $output;
}
echo getData2('table');
// /* output name=table&limit=50&page=1 */
echo getData2('table',20);
/* output name=table&limit=20&page=1 */
echo getData2('table',NULL,3);
/* output name=table&limit=50&page=3 */
?>
Hope this will help someone
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
Try This.
function getData($name, $limit = NULL, $page = '1') {
if (!$limit){
$limit = 50;
}
}
getData('some name', '', '23');
You can not skip middle parameter in your function call. But, you can work around with this:
function_call('1', '2', '3'); // Pass with parameter.
function_call('1', null, '3'); // Pass without parameter.
Function:
function function_call($a, $b='50', $c){
if(isset($b)){
echo $b;
}
else{
echo '50';
}
}
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.
<?php
define('DEFAULT_LIMIT', 50);
define('DEFAULT_PAGE', 1);
function getData($name, $limit = null, $page = null) {
$limit = is_null($limit) ? DEFAULT_LIMIT : $limit;
$page = is_null($page) ? DEFAULT_PAGE : $page;
...
}
?>
Hope this helps.
getData('some name');
just do not pass them and the default value will be accepted

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

How would I skip optional arguments in a function call?

OK I totally forgot how to skip arguments in PHP.
Lets say I have:
function getData($name, $limit = '50', $page = '1') {
...
}
How would I call this function so that the middle parameter takes the default value (ie. '50')?
getData('some name', '', '23');
Would the above be correct? I can't seem to get this to work.
Your post is correct.
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.
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.
There's no way to "skip" an argument other than to specify a default like false or null.
Since PHP lacks some syntactic sugar when it comes to this, you will often see something like this:
checkbox_field(array(
'name' => 'some name',
....
));
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.
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.
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 feature is implemented in PHP 8.0
PHP 8 introduced named arguments
which:
allows skipping default values arbitrarily
The documentation for reference
No changes necessary to use this feature:
lets use OPs function function getData($name, $limit = '50', $page = '1')
Usage
getData(name: 'some name', page: '23');
Native functions will also use this feature
htmlspecialchars($string, double_encode: false);
// Same as
htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);
Netbeans IDE 12.3 Feature Supported
This feature is supported, with the exception of code completion for named arguments, looks better ;)
For any parameter skipped (you have to) go with the default parameter, to be on the safe side.
(Settling for null where the default parameter is '' or similar or vice versa will get you into troublew...)
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)
You can't skip arguments but you can use array parameters and you need to define only 1 parameter, which is an array of parameters.
function myfunction($array_param)
{
echo $array_param['name'];
echo $array_param['age'];
.............
}
And you can add as many parameters you need, you don't need to define them. When you call the function, you put your parameters like this:
myfunction(array("name" => "Bob","age" => "18", .........));
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.
https://www.experts-exchange.com/articles/18409/Using-Named-Parameters-in-PHP-Function-Calls.html
I had to make a Factory with optional parameters, my workaround was to use the null coalescing operator:
public static function make(
string $first_name = null,
string $last_name = null,
string $email = null,
string $subject = null,
string $message = null
) {
$first_name = $first_name ?? 'First';
$last_name = $last_name ?? 'Last';
$email = $email ?? 'foo#bar.com';
$subject = $subject ?? 'Some subject';
$message = $message ?? 'Some message';
}
Usage:
$factory1 = Factory::make('First Name Override');
$factory2 = Factory::make(null, 'Last Name Override');
$factory3 = Factory::make(null, null, null, null 'Message Override');
Not the prettiest thing, but might be a good pattern to use in Factories for tests.
Well as everyone else already said, that what you want won't be possible in PHP without adding any code lines in the function.
But you can place this piece of code at the top of a function to get your functionality:
foreach((new ReflectionFunction(debug_backtrace()[0]["function"]))->getParameters() as $param) {
if(empty(${$param->getName()}) && $param->isOptional())
${$param->getName()} = $param->getDefaultValue();
}
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.
Demo
Set the limit to null
function getData($name, $limit = null, $page = '1') {
...
}
and call to that function
getData('some name', null, '23');
if you want to set the limit you can pass as an argument
getData('some name', 50, '23');
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);
(which is just a glorified version of the less formal parameter array technique)
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 */);
This snippet:
function getData($name, $options) {
$default = array(
'limit' => 50,
'page' => 2,
);
$args = array_merge($default, $options);
print_r($args);
}
getData('foo', array());
getData('foo', array('limit'=>2));
getData('foo', array('limit'=>10, 'page'=>10));
Answer is :
Array
(
[limit] => 50
[page] => 2
)
Array
(
[limit] => 2
[page] => 2
)
Array
(
[limit] => 10
[page] => 10
)
This is what I would do:
<?php
function getData($name, $limit = '', $page = '1') {
$limit = (EMPTY($limit)) ? 50 : $limit;
$output = "name=$name&limit=$limit&page=$page";
return $output;
}
echo getData('table');
/* output name=table&limit=50&page=1 */
echo getData('table',20);
/* name=table&limit=20&page=1 */
echo getData('table','',5);
/* output name=table&limit=50&page=5 */
function getData2($name, $limit = NULL, $page = '1') {
$limit = (ISSET($limit)) ? $limit : 50;
$output = "name=$name&limit=$limit&page=$page";
return $output;
}
echo getData2('table');
// /* output name=table&limit=50&page=1 */
echo getData2('table',20);
/* output name=table&limit=20&page=1 */
echo getData2('table',NULL,3);
/* output name=table&limit=50&page=3 */
?>
Hope this will help someone
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
Try This.
function getData($name, $limit = NULL, $page = '1') {
if (!$limit){
$limit = 50;
}
}
getData('some name', '', '23');
You can not skip middle parameter in your function call. But, you can work around with this:
function_call('1', '2', '3'); // Pass with parameter.
function_call('1', null, '3'); // Pass without parameter.
Function:
function function_call($a, $b='50', $c){
if(isset($b)){
echo $b;
}
else{
echo '50';
}
}
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.
<?php
define('DEFAULT_LIMIT', 50);
define('DEFAULT_PAGE', 1);
function getData($name, $limit = null, $page = null) {
$limit = is_null($limit) ? DEFAULT_LIMIT : $limit;
$page = is_null($page) ? DEFAULT_PAGE : $page;
...
}
?>
Hope this helps.
getData('some name');
just do not pass them and the default value will be accepted

Categories