问题
Is it possible in PHP 4/5 to specify a named optional parameter when calling, 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
Thanks
回答1:
No, it is not possible : 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 :
foo(array(
'a' => 'hello',
));
foo(array(
'a' => 'hello',
'c' => 'glop',
));
foo(array(
'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 optionnal parameters, for instance...
回答2:
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.
回答3:
No, it isn't.
The only way you can somewhat do that is by using arrays with named keys and what not.
回答4:
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;
}
回答5:
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");
回答6:
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'
));
回答7:
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.
回答8:
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
回答9:
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))
回答10:
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); }
回答11:
Try function test ($a="",$b="",&$c=""){}
Putting & before the $c
回答12:
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
回答13:
Simple answer. No you can't.
You could try getting around it by passing in an object/array or using some other Dependency injection patterns.
Also, try to use nulls rather than empty strings as it's more definite to test for their existence using is_null()
eg:
function test ($a=null,$b=null,$c=null){
if (is_null($a) {
//do something about $a
}
if (is_null($b) {
//do something about $b
}
if (is_null($c) {
//do something about $c
}
}
to call this:
test(null,null,"Hello");
回答14:
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
}
回答15:
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.
回答16:
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
回答17:
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.
来源:https://stackoverflow.com/questions/1342908/named-php-optional-arguments