関数/メソッドを呼び出すときに名前付きのオプションのパラメーターを指定し、指定したくないものをスキップすることはPHPで可能ですか(Pythonのように)?
何かのようなもの:
function foo($a, $b = '', $c = '') {
// whatever
}
foo("hello", $c="bar"); // we want $b as the default, but specify $c
関数/メソッドを呼び出すときに名前付きのオプションのパラメーターを指定し、指定したくないものをスキップすることはPHPで可能ですか(Pythonのように)?
何かのようなもの:
function foo($a, $b = '', $c = '') {
// whatever
}
foo("hello", $c="bar"); // we want $b as the default, but specify $c
いいえ、できません。3番目のパラメーターを渡す場合は、2番目のパラメーターを渡す必要があります。また、名前付きパラメーターも使用できません。
例えば :
function foo($params) {
var_dump($params);
}
そしてそれをこのように呼ぶ:(キー/値の配列)
foo([
'a' => 'hello',
]);
foo([
'a' => 'hello',
'c' => 'glop',
]);
foo([
'a' => 'hello',
'test' => 'another one',
]);
この出力を取得します:
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)
しかし、私はこの解決策が本当に好きではありません:
したがって、これは非常に特殊な場合にのみ使用します。たとえば、オプションのパラメーターが多数ある関数の場合は...
いいえ、PHP は引数を名前で渡すことはできません。
多くの引数を取る関数があり、それらすべてにデフォルト値がある場合は、代わりに関数が引数の配列を受け入れるようにすることを検討できます。
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
}
いいえ、そうではありません。
それをいくらか行うことができる唯一の方法は、名前付きキーを持つ配列を使用することです。
PHP 5.4 では、省略形の配列構文があります (面倒な "array" で配列を指定し、代わりに "[]" を使用する必要はありません)。
多くの方法で名前付きパラメーターを模倣できます。1 つの適切で簡単な方法は次のとおりです。
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;
}
それは正確にはきれいではありませんが、それはトリックを行います、と言う人もいるかもしれません.
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'
));
配列の代わりにオブジェクトを渡すことで、phpdoc とデフォルトを設定する機能を保持できます。
class FooOptions {
$opt1 = 'x';
$opt2 = 'y';
/* etc */
};
必要に応じて、関数呼び出しで厳密な型チェックを行うこともできます。
function foo (FooOptions $opts) {
...
}
もちろん、FooOptions オブジェクトをさらに冗長に設定することで、その代償を払うこともできます。残念ながら、完全に無料の乗車はありません。
通常はできませんが、名前付き引数を PHP 関数に渡す方法はたくさんあると思います。個人的には、配列を使用して定義を中継し、渡す必要があるものを呼び出すだけです。
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();
ここのライブ例: http://sandbox.onlinephpfunctions.com/code/d7f27c6e504737482d396cbd6cdf1cc118e8c1ff
10個の引数を渡す必要があり、そのうちの3つが本当に必要なデータである場合、次のような関数に渡すのはスマートではありません
return myfunction(false,false,10,false,false,"date",false,false,false,"desc");
私が提供しているアプローチでは、10 個の引数のいずれかを配列に設定できます。
$arr['count']=10;
$arr['type']="date";
$arr['order']="desc";
return myfunction($arr);
私のブログに、このプロセスをより詳細に説明した投稿があります。
http://www.tbogard.com/2013/03/07/passing-named-arguments-to-a-function-in-php
PHPでは、引数の順序が重要です。特定の引数を場違いに指定することはできませんが、代わりに、関数の値がNULL値であることを気にしない限り、NULLを渡すことで引数をスキップできます。
foo("hello", NULL, "bar");
本当に必要な場合は、反射を試してください。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
これが私が使ってきたものです。関数定義は、オプションの名前付き引数を指定するオプションの配列引数を 1 つ取ります。
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.
...
}
通常、名前付き引数なしで呼び出すことができます。
func("xyzzy")
オプションの名前付き引数を指定するには、オプションの配列に渡します。
func("xyzzy", Array('foo' => 5.7))
私はそうは思いません...たとえば、3 つのパラメーターを持つsubstr関数を呼び出す必要があり、$start を設定せずに $length を設定したい場合は、そうする必要があります。
substr($str,0,10);
これをオーバーライドする良い方法は、常にパラメーターに配列を使用することです
Pythonの方法ではできません。とにかく、連想配列を渡して、配列エントリを名前で使用することができます。
function test ($args=array('a'=>'','b'=>'','c'=>''))
{
// do something
}
test(array('c'=>'Hello'));
これによってタイピングが減ることはありませんが、少なくともより説明的になり、呼び出しで引数の名前が表示および読み取り可能になります。
Drupal が使用する連想配列パターンを使用するだけです。オプションのデフォルトの引数について$options
は、連想配列である引数を受け入れるだけです。次に、配列+
演算子を使用して、配列に不足しているキーを設定します。
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.
回避策は次のとおりです。
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');
別の方法: 個人的には、この方法を使用します。
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']);
両方の例を印刷します。
最初の呼び出し:
2 回目の呼び出し:
いいえ、そうではありません。使用できる代替手段がいくつかあります。
test(null,null,"hello")
または配列を渡します。
test(array('c' => "hello"));
次に、関数は次のようになります。
function test($array) {
$c = isset($array[c]) ? $array[c] : '';
}
または間に関数を追加しますが、これはお勧めしません:
function ctest($c) { test('','',$c); }
要するに、リフレクションと型付き変数を使用することで、時にはそうです。しかし、これはおそらくあなたが求めているものではないと思います。
あなたの問題に対するより良い解決策は、関数が関数内の欠落している引数を自分で処理するときに、おそらく 3 つの引数を渡すことです。
<?php
function test(array $params)
{
//Check for nulls etc etc
$a = $params['a'];
$b = $params['b'];
...etc etc
}