Call PHP function - php

I have php function by multi parameter. I want to call this function with setting only last argument. Simple way is setting other argument empty. But it isn't good.
Is any way to call this function with setting last argument and without setting other argument?
See this example:
function MyFunction($A, $B, $C, $D, $E, $F)
{
//// Do something
}
//// Simple way
MyFunction("", "", "", "", "", "Value");
//// My example
MyFunction(argument6: "Value")

My suggestion is use array instead of using number of argument, For example your function call should be like this.
$params[6] = 'value';
MyFunction($params);
For identify that sixth parameter has set
function MyFunction($params){
If ( isset($params[6]) ) // parameter six has value
}
I hope that it will be a alternate way

In the context of the question, this works.
You can use each array key as a variable like $A, $B, ...
But you have to be careful not to post $args with the old values you have previously set.
<?php
$args = array('A'=>'', 'B'=>'', 'C'=>'', 'D'=>'', 'E'=>'', 'F'=>'');
function MyFunction($args)
{
foreach($args as $key => $value)
$$key = $value;
echo $F;
//// Do something
}
$args['F'] = 'Value';
Myfunction($args);

Use an array as parameter and use type hinting and empty array as default value in function definition. Provide default values inside the function and override them by user values.
function MyFunction(array $args = []) {
// Provide default values
$defaults = [
'A' => 0,
'B' => 0,
'C' => 0,
'D' => 0,
'E' => 0,
'F' => 0
];
foreach ($defaults as $key => $val) {
if (!array_key_exists($key, $args)) {
$args[$key] = $val;
}
}
echo '<pre>';
print_r($args);
echo '</pre>';
}
MyFunction();
MyFunction(['F' => 77]);

Related

Passing parameter to a function by parameter name? [duplicate]

Is it possible in PHP to specify a named optional parameter when calling a function/method, skipping the ones you don't want to specify (like in python)?
Something like:
function foo($a, $b = '', $c = '') {
// whatever
}
foo("hello", $c="bar"); // we want $b as the default, but specify $c
No, it is not possible (before PHP 8.0): if you want to pass the third parameter, you have to pass the second one. And named parameters are not possible either.
A "solution" would be to use only one parameter, an array, and always pass it... But don't always define everything in it.
For instance :
function foo($params) {
var_dump($params);
}
And calling it this way : (Key / value array)
foo([
'a' => 'hello',
]);
foo([
'a' => 'hello',
'c' => 'glop',
]);
foo([
'a' => 'hello',
'test' => 'another one',
]);
Will get you this output :
array
'a' => string 'hello' (length=5)
array
'a' => string 'hello' (length=5)
'c' => string 'glop' (length=4)
array
'a' => string 'hello' (length=5)
'test' => string 'another one' (length=11)
But I don't really like this solution :
You will lose the phpdoc
Your IDE will not be able to provide any hint anymore... Which is bad
So I'd go with this only in very specific cases -- for functions with lots of optional parameters, for instance...
PHP 8 was released on November 26, 2020 with a new feature called named arguments.
In this major version release, "named parameters" (aka "named arguments") afford developers some really cool new techniques when calling native and custom functions.
The custom function in this question can now be called with the first parameter (because there is no default for it) and then only the third parameter passed by using named parameters like this: (Demo)
function foo($a, $b = '', $c = '') {
echo $a . '&' . $b . '&' . $c;
}
foo("hello", c: "bar");
// output: hello&&bar
Notice that the second parameter did not need to be declared in the function call because it has a default value defined -- the default value is automatically used within the function body.
Part of the beauty of this new feature is that you don't need to be careful about the order of your named parameters -- the order of their declaration is irrelevant. foo(c: "bar", a: "hello"); works just the same. Having the ability to "skip" declarations and write declarative parameters will improve the readability of your scripts. The only downside of this new feature is that there will be a little bit more bloat in the function calls, but I (and many others) think the benefits outweigh this "cost".
Here is an example of a native function omitting the limit parameter, writing the parameters out of their normal order, and declaring a reference variable. (Demo)
echo preg_replace(
subject: 'Hello 7',
pattern: '/[a-z ]/',
count: $counted,
replacement: ''
)
. " & " . $counted;
// output: H7 & 5
There is more to tell about this new feature. You can even use an associative array to pass the named parameters to the function where the spread/splat operator can be used to unpack the data!
(*notice the slight difference in declaring the reference variable.) (Demo)
$params = [
'subject' => 'Hello 7', // normally third parameter
'pattern' => '/[a-z ]/', // normally first parameter
// 'limit' // normally fourth parameter, omitted for this demonstration; the default -1 will be used
'count' => &$counted, // normally fifth parameter
// ^-- don't forget to make it modifiable!
'replacement' => '', // normally second parameter
];
echo preg_replace(...$params) . " & " . $counted;
// same output as the previous snippet
For more information, here are a few leads that explain further about this feature and some common related errors: (I have no affiliation with the following sites)
https://wiki.php.net/rfc/named_params
https://stitcher.io/blog/php-8-named-arguments
https://stitcher.io/blog/why-we-need-named-params-in-php
No, PHP cannot pass arguments by name.
If you have a function that takes a lot of arguments and all of them have default values you can consider making the function accept an array of arguments instead:
function test (array $args) {
$defaults = array('a' => '', 'b' => '', 'c' => '');
$args = array_merge($defaults, array_intersect_key($args, $defaults));
list($a, $b, $c) = array_values($args);
// an alternative to list(): extract($args);
// you can now use $a, $b, $c
}
See it in action.
No, it isn't.
The only way you can somewhat do that is by using arrays with named keys and what not.
As of PHP 5.4 you have shorthand array syntax (not nessecary to specify arrays with cumbersome "array" and instead use "[]").
You can mimic named parameters in many ways, one good and simple way might be:
bar('one', ['a1' => 'two', 'bar' => 'three', 'foo' => 'four']);
// output: twothreefour
function bar ($a1, $kwargs = ['bar' => null, 'foo' => null]) {
extract($kwargs);
echo $a1;
echo $bar;
echo $foo;
}
You can keep the phpdoc and the ability to set defaults by passing an object instead of an array, e.g.
class FooOptions {
$opt1 = 'x';
$opt2 = 'y';
/* etc */
};
That also lets you do strict type checking in your function call, if you want to:
function foo (FooOptions $opts) {
...
}
Of course, you might pay for that with extra verbosity setting up the FooOptions object. There's no totally-free ride, unfortunately.
It's not exactly pretty, but it does the trick, some might say.
class NamedArguments {
static function init($args) {
$assoc = reset($args);
if (is_array($assoc)) {
$diff = array_diff(array_keys($assoc), array_keys($args));
if (empty($diff)) return $assoc;
trigger_error('Invalid parameters: '.join(',',$diff), E_USER_ERROR);
}
return array();
}
}
class Test {
public static function foobar($required, $optional1 = '', $optional2 = '') {
extract(NamedArguments::init(get_defined_vars()));
printf("required: %s, optional1: %s, optional2: %s\n", $required, $optional1, $optional2);
}
}
Test::foobar("required", "optional1", "optional2");
Test::foobar(array(
'required' => 'required',
'optional1' => 'optional1',
'optional2' => 'optional2'
));
Normally you can't but I think there a lot of ways to pass named arguments to a PHP function. Personally I relay on the definition using arrays and just call what I need to pass:
class Test{
public $a = false;
private $b = false;
public $c = false;
public $d = false;
public $e = false;
public function _factory(){
$args = func_get_args();
$args = $args[0];
$this->a = array_key_exists("a",$args) ? $args["a"] : 0;
$this->b = array_key_exists("b",$args) ? $args["b"] : 0;
$this->c = array_key_exists("c",$args) ? $args["c"] : 0;
$this->d = array_key_exists("d",$args) ? $args["d"] : 0;
$this->e = array_key_exists("e",$args) ? $args["e"] : 0;
}
public function show(){
var_dump($this);
}
}
$test = new Test();
$args["c"]=999;
$test->_factory($args);
$test->show();
live example here:
http://sandbox.onlinephpfunctions.com/code/d7f27c6e504737482d396cbd6cdf1cc118e8c1ff
If I have to pass 10 arguments, and 3 of them are the data I really need, is NOT EVEN SMART to pass into the function something like
return myfunction(false,false,10,false,false,"date",false,false,false,"desc");
With the approach I'm giving, you can setup any of the 10 arguments into an array:
$arr['count']=10;
$arr['type']="date";
$arr['order']="desc";
return myfunction($arr);
I have a post in my blog explaining this process in more details.
http://www.tbogard.com/2013/03/07/passing-named-arguments-to-a-function-in-php
With PHP, the order of arguments is what matters. You can't specify a particular argument out of place, but instead, you can skip arguments by passing a NULL, as long as you don't mind the value in your function having a NULL value.
foo("hello", NULL, "bar");
If you really really want, try the reflection.
And skip with null.
function getDefaultValueByNull($fn, $inputs) {
$ref = new ReflectionFunction($fn);
$args = array_map(function($p) {
return [
$p->getName(),
$p->isDefaultValueAvailable() ? $p->getDefaultValue() : NULL,
];
}, $ref->getParameters());
foreach($inputs as $i=>$val) { if ($val!==NULL) $args[$i][1] = $val; }
return array_column($args, 1, 0);
}
function sum($a=9, $b) {
extract(getDefaultValueByNull(__FUNCTION__, func_get_args()));
return $a+$b;
}
echo sum(NULL, 1); // 10
Here's what I've been using. A function definition takes one optional array argument which specifies the optional named arguments:
function func($arg, $options = Array()) {
$defaults = Array('foo' => 1.0,
'bar' => FALSE);
$options = array_merge($default, $options);
// Normal function body here. Use $options['foo'] and
// $options['bar'] to fetch named parameter values.
...
}
You can normally call without any named arguments:
func("xyzzy")
To specify an optional named argument, pass it in the optional array:
func("xyzzy", Array('foo' => 5.7))
No not really. There are a few alternatives to it you could use.
test(null,null,"hello")
Or pass an array:
test(array('c' => "hello"));
Then, the function could be:
function test($array) {
$c = isset($array[c]) ? $array[c] : '';
}
Or add a function in between, but i would not suggest this:
function ctest($c) { test('','',$c); }
I dont think so...
If you need to call, for example, the substr function, that has 3 params, and want to set the $length without set the $start, you'll be forced to do so.
substr($str,0,10);
a nice way to override this is to always use arrays for parameters
In very short, sometimes yes, by using reflection and typed variables. However I think this is probably not what you are after.
A better solution to your problem is probably to pass in the 3 arguments as functions handle the missing one inside your function yourself
<?php
function test(array $params)
{
//Check for nulls etc etc
$a = $params['a'];
$b = $params['b'];
...etc etc
}
You can't do it the python way. Anway, you could pass an associative array and than use the array entries by their name:
function test ($args=array('a'=>'','b'=>'','c'=>''))
{
// do something
}
test(array('c'=>'Hello'));
This doesn't reduce the typing, but at least it's more descriptive, having the arguments' names visible and readable in the call.
Here is a work around:
function set_param_defaults($params) {
foreach($params['default_values'] as $arg_name => $arg_value) {
if (!isset($params[$arg_name])) {
$params[$arg_name] = $arg_value;
}
}
return $params;
}
function foo($z, $x = null, $y = null) {
$default_values = ['x' => 'default value for x', 'y' => 'default value for y'];
$params = set_param_defaults(get_defined_vars());
print "$z\n";
print $params['x'] . "\n";
print $params['y'] . "\n";
}
foo('set z value', null, 'set y value');
print "\n";
foo('set z value', 'set x value');
ALTERNATIVELY:
Personally I would go with this method.
function foo($z, $x_y) {
$x_y += ['x' => 'default value for x', 'y' => 'default value for y'];
print "$z\n";
print $x_y['x'] . "\n";
print $x_y['y'] . "\n";
}
foo('set z value', ['y' => 'set y value']);
print "\n";
foo('set z value', ['x' => 'set x value']);
Print outs for both examples.
1st call:
set z value
default value for x
set y value
2nd call:
set z value
set x value
default value for y
Just use the associative array pattern Drupal uses. For optional defaulted arguments, just accept an $options argument which is an associative array. Then use the array + operator to set any missing keys in the array.
function foo ($a_required_parameter, $options = array()) {
$options += array(
'b' => '',
'c' => '',
);
// whatever
}
foo('a', array('c' => 'c’s value')); // No need to pass b when specifying c.

php function to unset variables passed by reference

currently i'm using this php function :
function if_exist(&$argument, $default = '')
{
if (isset ($argument))
{
echo $argument;
}
else
{
echo $default;
}
}
i want this function to unset the variables $argument(passed by reference) and $default just after echoing their value, how can i do this?
Thanks in advance.
According to the manual for unset:
If a variable that is PASSED BY REFERENCE is unset() inside of a
function, only the local variable is destroyed. The variable in the
calling environment will retain the same value as before unset() was
called.
I assume this is the issue you're encountering. So, my suggestion is to simply set $argument to NULL. Which, according to the NULL docs will "remove the variable and unset its value.".
For example:
$argument = NULL;
$default is passed by value, so it cannot be unset (except in the local scope).
As you undoubtedly discovered, unset() simply unsets the reference to $argument. You can (sort of) unset $argument like this:
$argument = null;
the only way to do this with a function is using globals.
//To unset() a global variable inside of a function,
// then use the $GLOBALS array to do so:
<?php
function foo()
{
unset($GLOBALS['bar']);
}
$bar = "something";
foo();
?>
If var is not array, and passed by reference, unset is actually unset the pointer, so it will not affect the original.
However if the var is array, you can unset its keys. eg:
$arr = [
'a' => 1,
'b' => ['c' => 3],
];
function del($key, &$arr) {
$key = explode('.', $key);
$end = array_pop($key);
foreach ($key as $k) {
if (is_array($arr[$k]) {
$arr = &$arr[$k];
} else {
return; // Error - invalid key -- doing nothing
}
}
unset($arr[$end]);
}
del('b.c', $arr); // $arr = ['a' => 1, 'b' => []]
del('b', $arr); // $arr = ['a' => 1]

What is the best way of reading parameters in functions?

I've created several helper functions which I use when creating templates for Wordpress.
An example is this:
function the_related_image_scaled($w="150", $h="150", $cropratio="1:1", $alt="", $key="related" )
The problem is, if I only want to pass along the $alt parameter, I also have to populate $w, $h and $cropratio.
In one of my plugins, I use the following code:
function shortcode_display_event($attr) {
extract(shortcode_atts(array(
'type' => 'simple',
'parent_id' => '',
'category' => 'Default',
'count' => '10',
'link' => ''
), $attr));
$ec->displayCalendarList($data);
}
This allows me to call the function only using e.g.count=30.
How can I achieve the same thing in my own functions?
SOLUTION
Thanks to my name brother (steven_desu), I have come up with a solution that works.
I added a extra function (which I found on the net) to create value - pair from a string.
The code looks as follows:
// This turns the string 'intro=mini, read_more=false' into a value - pair array
function pairstr2Arr ($str, $separator='=', $delim=',') {
$elems = explode($delim, $str);
foreach( $elems as $elem => $val ) {
$val = trim($val);
$nameVal[] = explode($separator, $val);
$arr[trim(strtolower($nameVal[$elem][0]))] = trim($nameVal[$elem][1]);
}
return $arr;
}
function some_name($attr) {
$attr = pairstr2Arr($attr);
$result = array_merge(array(
'intro' => 'main',
'num_words' => '20',
'read_more' => 'true',
'link_text' => __('Read more')
), $attr);
extract($result);
// $intro will no longer contain'main' but will contain 'mini'
echo $intro;
}
some_name('intro=mini, read_more=false')
Info
With good feedback from Pekka, I googled and found some info regarding the Named Arguments and why it's not in PHP: http://www.seoegghead.com/software/php-parameter-skipping-and-named-parameters.seo
I would suggest using array_merge() and extract() at the beginning of your function, then passing parameters as arrays if this is a possibility.
function whatever($new_values){
$result = array_merge(array(
"var1" => "value1",
"var2" => "value2",
"var3" => "value3"
), $new_values);
extract($result);
echo "$var1, $var2, $var3";
}
whatever(array("var2"=>"new_value"));
The above will output:
value1, new_value, value3
it's a bit sloppy and uses more memory since it has to allocate the arrays, so it's the less efficient solution. But it does allow you to avoid redundancy. I'm sure a better method exists using magic meta-code, but I can't think of it off-hand.
Say this is your function:
function related_image_scaled($w="150", $h="150", $alt="", $key="related")
You can do this:
class ImageScaleParams {
public $w = 150;
public $h = 150;
public $cropratio = "1:1";
public $alt = "";
public $key = "related";
}
function related_image_scaled(ImageScaleParams $params) { ... }
Then call it like this:
$imgscale = new ImageScaleParams();
$imgscale.alt="New Alt";
related_image_scaled($imgscale);
You can also have various factories in ImageScaleParams such as:
class ImageScaleParams {
static function altFactory($alt) {
$imgscale = new ImageScaleParams();
$imgscale->alt = $alt;
return $imgscale;
}
}
Which you could call like this (equivalent to previous example):
related_image_scaled(ImageScaleParams::altFactory("New Alt"));
New Answer:
Could you not write the function using the extract function's default EXTR_OVERWRITE option?
function the_related_image_scaled($params) {
$w="150"; $h="150"; $cropratio="1:1"; $alt=""; $key="related";
extract($params);
//Do Stuff
}
Called with:
the_Related_image_scaled(array("alt"=>"Alt Text"));
You have the option of defaulting the parameters to null and only using them if they are not null:
function the_related_image_scaled($w=null, $h=null, $cropratio=null, $alt=null, $key = null) {
$output = //Get the base of the image tag
//including src leave a trailing space and don't close
if($w!==null) {
$output .= "width=\"$w\"";
}
//... Through all your parameters
return $output;
}
So only passing the alt parameter would look like:
echo the_related_image_scaled(null,null,null,$alt);

How to format a simple PHP array of strings?

I have this simple function which I pass in an array of strings:
function myfunction( $arg = array() )
{
// do stuff to $arg...
// return a $string;
}
Simple so far, but I need some of the strings in the $arg array to be formatted, while some remain unformatted. I can't figure out how to do it?
Say I run this $arg through myfunction():
echo myfunction( array( 'format me!', 'do not format me!' ) );
My tiny little brain can't figure out how to tell myfunction() that the first value in $arg array needs to have formatting, and it should not format the second value.
I thought about an associative array, but I think that could be the wrong approach because of having identical indexes.
echo myfunction( array( 'format' => 'hi', 'format' => 'bye', 'noformat' => 'foo');
Just looking for a "nudge" in the right direction.
EDIT 1:
Forgot to mention, I can only have one $arg array because I need the keys to be in a specific order.
EDIT 2:
The $arg array can have as many keys as the user wants.
You can do:
function myfunction(array $format, array $noformat) {
...
}
or
function myfunction(array $strings) {
foreach ($strings['format'] as $format) {
// do stuff
}
foreach ($strings['noformat'] as $noformat) {
// do stuff
}
}
with:
myfunction(array(
'format' => array('one', 'two', 'three'),
'noformat' => array('four', 'five', 'six'),
));
If (and only if) the strings are unique you can put them in the key instead of the value:
$strings = array(
'one' => true,
'two' => false,
'three' => false,
'four' => true,
);
myfunction($strings);
with:
function myfunction(array $strings) {
foreach ($strings as $k => $v) {
if ($v) {
// format string
}
}
}
But since you can't have duplicate keys this method falls down if you have repeated strings.
Instead of having myfunction() take an array as an argument, why not just have it take a single element as the argument. Then you can use array_map to process each element of the array.
Sort of like this:
function myfunction($element) {
if( do-formatting) {
//do your formatting stuff
$element = formatted-stuff
}
return $element
}
$arr = array("format me", "don't format me");
//This calls myfunction on each element of the array
//A new array is returned where each element has been replaced
//by the return value from myfunction.
$arr = array_map('myfunction', $arr);
Here is how I would to it.
The implementation of __tostring is not mandatory but is syntax sugar inside the myFunction.
<?php
class MyString{
private $_value;
public $to_format;
public function __construct($str, $to_format = true){
$this->_value = $str;
$this->to_format = $to_format;
}
public function __tostring(){
return $this->_value;
}
}
$args = array( new MyString('format me'), new MyString('Not me!', false) );
This is oddly similar to how table rows are formatted (with a different formatting function for each row). I would provide the data as a single array, then provide formatting information as a second array based on keys. For instance:
function rowFormatter(Array $data, Array $format=array()) {
ob_start();
foreach ($data as $key => $value) {
if (isset($format[$key]))
echo call_user_func($format[$key],$value);
else
echo $value;
}
return ob_get_clean();
}
function makeBold($x) { return '<b>'.$x.'</b>'; }
rowFormatter(array( "Hello", "Mister" ), array( 0 => 'makeBold' ));
I don't know what these strings you are formatting actually represent, so I used generic naming on these classes:
class LineItem
{
var $value;
function __construct($val)
{
$this->value = $val;
}
function __toString()
{
return $this->value;
}
function getFormatted( $formatter )
{
return $this->value;
}
}
class FormattedLineItem extends LineItem
{
function getFormatted( $formatter )
{
return $formatter( $this->value );
}
}
function myfunction( $arr=array() )
{
$fnFormat = function($str) {
return ucwords($str);
};
foreach($arr as $obj)
{
$str = $obj->getFormatted($fnFormat);
echo "$str\n";
}
}
$arr = array(
new FormattedLineItem('format me!'),
new LineItem('do not format me!')
);
myfunction($arr);
The idea is to use separate classes to distinguish between strings.

Does PHP allow named parameters so that optional arguments can be omitted from function calls?

Is it possible in PHP to specify a named optional parameter when calling a function/method, skipping the ones you don't want to specify (like in python)?
Something like:
function foo($a, $b = '', $c = '') {
// whatever
}
foo("hello", $c="bar"); // we want $b as the default, but specify $c
No, it is not possible (before PHP 8.0): if you want to pass the third parameter, you have to pass the second one. And named parameters are not possible either.
A "solution" would be to use only one parameter, an array, and always pass it... But don't always define everything in it.
For instance :
function foo($params) {
var_dump($params);
}
And calling it this way : (Key / value array)
foo([
'a' => 'hello',
]);
foo([
'a' => 'hello',
'c' => 'glop',
]);
foo([
'a' => 'hello',
'test' => 'another one',
]);
Will get you this output :
array
'a' => string 'hello' (length=5)
array
'a' => string 'hello' (length=5)
'c' => string 'glop' (length=4)
array
'a' => string 'hello' (length=5)
'test' => string 'another one' (length=11)
But I don't really like this solution :
You will lose the phpdoc
Your IDE will not be able to provide any hint anymore... Which is bad
So I'd go with this only in very specific cases -- for functions with lots of optional parameters, for instance...
PHP 8 was released on November 26, 2020 with a new feature called named arguments.
In this major version release, "named parameters" (aka "named arguments") afford developers some really cool new techniques when calling native and custom functions.
The custom function in this question can now be called with the first parameter (because there is no default for it) and then only the third parameter passed by using named parameters like this: (Demo)
function foo($a, $b = '', $c = '') {
echo $a . '&' . $b . '&' . $c;
}
foo("hello", c: "bar");
// output: hello&&bar
Notice that the second parameter did not need to be declared in the function call because it has a default value defined -- the default value is automatically used within the function body.
Part of the beauty of this new feature is that you don't need to be careful about the order of your named parameters -- the order of their declaration is irrelevant. foo(c: "bar", a: "hello"); works just the same. Having the ability to "skip" declarations and write declarative parameters will improve the readability of your scripts. The only downside of this new feature is that there will be a little bit more bloat in the function calls, but I (and many others) think the benefits outweigh this "cost".
Here is an example of a native function omitting the limit parameter, writing the parameters out of their normal order, and declaring a reference variable. (Demo)
echo preg_replace(
subject: 'Hello 7',
pattern: '/[a-z ]/',
count: $counted,
replacement: ''
)
. " & " . $counted;
// output: H7 & 5
There is more to tell about this new feature. You can even use an associative array to pass the named parameters to the function where the spread/splat operator can be used to unpack the data!
(*notice the slight difference in declaring the reference variable.) (Demo)
$params = [
'subject' => 'Hello 7', // normally third parameter
'pattern' => '/[a-z ]/', // normally first parameter
// 'limit' // normally fourth parameter, omitted for this demonstration; the default -1 will be used
'count' => &$counted, // normally fifth parameter
// ^-- don't forget to make it modifiable!
'replacement' => '', // normally second parameter
];
echo preg_replace(...$params) . " & " . $counted;
// same output as the previous snippet
For more information, here are a few leads that explain further about this feature and some common related errors: (I have no affiliation with the following sites)
https://wiki.php.net/rfc/named_params
https://stitcher.io/blog/php-8-named-arguments
https://stitcher.io/blog/why-we-need-named-params-in-php
No, PHP cannot pass arguments by name.
If you have a function that takes a lot of arguments and all of them have default values you can consider making the function accept an array of arguments instead:
function test (array $args) {
$defaults = array('a' => '', 'b' => '', 'c' => '');
$args = array_merge($defaults, array_intersect_key($args, $defaults));
list($a, $b, $c) = array_values($args);
// an alternative to list(): extract($args);
// you can now use $a, $b, $c
}
See it in action.
No, it isn't.
The only way you can somewhat do that is by using arrays with named keys and what not.
As of PHP 5.4 you have shorthand array syntax (not nessecary to specify arrays with cumbersome "array" and instead use "[]").
You can mimic named parameters in many ways, one good and simple way might be:
bar('one', ['a1' => 'two', 'bar' => 'three', 'foo' => 'four']);
// output: twothreefour
function bar ($a1, $kwargs = ['bar' => null, 'foo' => null]) {
extract($kwargs);
echo $a1;
echo $bar;
echo $foo;
}
You can keep the phpdoc and the ability to set defaults by passing an object instead of an array, e.g.
class FooOptions {
$opt1 = 'x';
$opt2 = 'y';
/* etc */
};
That also lets you do strict type checking in your function call, if you want to:
function foo (FooOptions $opts) {
...
}
Of course, you might pay for that with extra verbosity setting up the FooOptions object. There's no totally-free ride, unfortunately.
It's not exactly pretty, but it does the trick, some might say.
class NamedArguments {
static function init($args) {
$assoc = reset($args);
if (is_array($assoc)) {
$diff = array_diff(array_keys($assoc), array_keys($args));
if (empty($diff)) return $assoc;
trigger_error('Invalid parameters: '.join(',',$diff), E_USER_ERROR);
}
return array();
}
}
class Test {
public static function foobar($required, $optional1 = '', $optional2 = '') {
extract(NamedArguments::init(get_defined_vars()));
printf("required: %s, optional1: %s, optional2: %s\n", $required, $optional1, $optional2);
}
}
Test::foobar("required", "optional1", "optional2");
Test::foobar(array(
'required' => 'required',
'optional1' => 'optional1',
'optional2' => 'optional2'
));
Normally you can't but I think there a lot of ways to pass named arguments to a PHP function. Personally I relay on the definition using arrays and just call what I need to pass:
class Test{
public $a = false;
private $b = false;
public $c = false;
public $d = false;
public $e = false;
public function _factory(){
$args = func_get_args();
$args = $args[0];
$this->a = array_key_exists("a",$args) ? $args["a"] : 0;
$this->b = array_key_exists("b",$args) ? $args["b"] : 0;
$this->c = array_key_exists("c",$args) ? $args["c"] : 0;
$this->d = array_key_exists("d",$args) ? $args["d"] : 0;
$this->e = array_key_exists("e",$args) ? $args["e"] : 0;
}
public function show(){
var_dump($this);
}
}
$test = new Test();
$args["c"]=999;
$test->_factory($args);
$test->show();
live example here:
http://sandbox.onlinephpfunctions.com/code/d7f27c6e504737482d396cbd6cdf1cc118e8c1ff
If I have to pass 10 arguments, and 3 of them are the data I really need, is NOT EVEN SMART to pass into the function something like
return myfunction(false,false,10,false,false,"date",false,false,false,"desc");
With the approach I'm giving, you can setup any of the 10 arguments into an array:
$arr['count']=10;
$arr['type']="date";
$arr['order']="desc";
return myfunction($arr);
I have a post in my blog explaining this process in more details.
http://www.tbogard.com/2013/03/07/passing-named-arguments-to-a-function-in-php
With PHP, the order of arguments is what matters. You can't specify a particular argument out of place, but instead, you can skip arguments by passing a NULL, as long as you don't mind the value in your function having a NULL value.
foo("hello", NULL, "bar");
If you really really want, try the reflection.
And skip with null.
function getDefaultValueByNull($fn, $inputs) {
$ref = new ReflectionFunction($fn);
$args = array_map(function($p) {
return [
$p->getName(),
$p->isDefaultValueAvailable() ? $p->getDefaultValue() : NULL,
];
}, $ref->getParameters());
foreach($inputs as $i=>$val) { if ($val!==NULL) $args[$i][1] = $val; }
return array_column($args, 1, 0);
}
function sum($a=9, $b) {
extract(getDefaultValueByNull(__FUNCTION__, func_get_args()));
return $a+$b;
}
echo sum(NULL, 1); // 10
Here's what I've been using. A function definition takes one optional array argument which specifies the optional named arguments:
function func($arg, $options = Array()) {
$defaults = Array('foo' => 1.0,
'bar' => FALSE);
$options = array_merge($default, $options);
// Normal function body here. Use $options['foo'] and
// $options['bar'] to fetch named parameter values.
...
}
You can normally call without any named arguments:
func("xyzzy")
To specify an optional named argument, pass it in the optional array:
func("xyzzy", Array('foo' => 5.7))
No not really. There are a few alternatives to it you could use.
test(null,null,"hello")
Or pass an array:
test(array('c' => "hello"));
Then, the function could be:
function test($array) {
$c = isset($array[c]) ? $array[c] : '';
}
Or add a function in between, but i would not suggest this:
function ctest($c) { test('','',$c); }
I dont think so...
If you need to call, for example, the substr function, that has 3 params, and want to set the $length without set the $start, you'll be forced to do so.
substr($str,0,10);
a nice way to override this is to always use arrays for parameters
In very short, sometimes yes, by using reflection and typed variables. However I think this is probably not what you are after.
A better solution to your problem is probably to pass in the 3 arguments as functions handle the missing one inside your function yourself
<?php
function test(array $params)
{
//Check for nulls etc etc
$a = $params['a'];
$b = $params['b'];
...etc etc
}
You can't do it the python way. Anway, you could pass an associative array and than use the array entries by their name:
function test ($args=array('a'=>'','b'=>'','c'=>''))
{
// do something
}
test(array('c'=>'Hello'));
This doesn't reduce the typing, but at least it's more descriptive, having the arguments' names visible and readable in the call.
Here is a work around:
function set_param_defaults($params) {
foreach($params['default_values'] as $arg_name => $arg_value) {
if (!isset($params[$arg_name])) {
$params[$arg_name] = $arg_value;
}
}
return $params;
}
function foo($z, $x = null, $y = null) {
$default_values = ['x' => 'default value for x', 'y' => 'default value for y'];
$params = set_param_defaults(get_defined_vars());
print "$z\n";
print $params['x'] . "\n";
print $params['y'] . "\n";
}
foo('set z value', null, 'set y value');
print "\n";
foo('set z value', 'set x value');
ALTERNATIVELY:
Personally I would go with this method.
function foo($z, $x_y) {
$x_y += ['x' => 'default value for x', 'y' => 'default value for y'];
print "$z\n";
print $x_y['x'] . "\n";
print $x_y['y'] . "\n";
}
foo('set z value', ['y' => 'set y value']);
print "\n";
foo('set z value', ['x' => 'set x value']);
Print outs for both examples.
1st call:
set z value
default value for x
set y value
2nd call:
set z value
set x value
default value for y
Just use the associative array pattern Drupal uses. For optional defaulted arguments, just accept an $options argument which is an associative array. Then use the array + operator to set any missing keys in the array.
function foo ($a_required_parameter, $options = array()) {
$options += array(
'b' => '',
'c' => '',
);
// whatever
}
foo('a', array('c' => 'c’s value')); // No need to pass b when specifying c.

Categories