3

デフォルト値を持つ膨大な数のパラメータを持つphp関数がいくつかあります。このようなもの:

function foo($a=0,$b=6,$c=2,...

立場上の議論の恐ろしさを避けるために何ができるのだろうか。引数セットのサブセットのみを使用して名前で関数を呼び出すことは可能ですか? 次のように:

foo($c=37)

ありがとう!

4

5 に答える 5

8

明らかに、 位置引数の恐ろしさを回避する最善の方法は、長く風通しの良い引数リストを持つ関数を避けることです。

単一の配列変数を介してほとんどのパラメーターを渡すことができるか、関数をリファクタリングして、それらをより小さなものに分割するか、クラスに結合する必要があります

于 2013-09-13T12:22:04.790 に答える
3

私はこの質問がどこから来たのかを完全に理解していますが、私は言わなければなりません.もしあなたの関数がオプションの一連の引数を必要とするなら、9/10あなたの関数には何か問題があります.
実生活での機能とは、何かを行う能力です。現実の世界では、椅子は座るものです。N本の足を持つことができますが、1 つの仕事をします。私がこれまで見てきた多くのコードでは、オプションの引数が多すぎる関数は、渡される引数に応じて異なるタスクを実行します。したがって、その関数には複数のタスクがあります。それは関数の目的ではありません!

ロジックを再考してください。ただし、関数が単一のジョブを実行する場合、どの引数が指定されているかに関係なく、@ OZ_ の答えが適切です。(クラス名またはインターフェイスを介した) 型ヒントは、これを行う正しい方法です。
連想配列も機能しますが、ifのような大量の'sを記述する必要がないようにするためです。

$a = 'default';
if (isset($args['a']))
{
    $a = $args['a'];
}
$b = isset($args['b']) ? $args['b'] : 'default';//or messy ternary-packed code

次のようなものを書くことを選択できます。

function someF(array $args)
{
    $a = $b = $c = $d = null;//all your arguments and default values
    foreach($args as $name => $val)
    {
        $$name = $val;
    }
    //function body
}
someF(range(1,3));//works, but sets ${'0'}, ${'1'}, ...
someF(array('a' => 1));//works fine
someF(array('a' => new stdClass));//is $a going to be the right type?

それでも、if's/ternary アプローチのように、値がどのタイプになるかを予測することはできません。また、渡される配列のタイプ (連想/数値) もわからないため、多くの変数を設定することになる可能性があります。いらない。さらに、今から数か月後にこのコードを読みやすく、デバッグしやすく、保守しやすいと思いますか?

一方、クラスまたはインターフェースを使用すると、次のようになります。

class ArgumentsForFunc
{
    private $a = null;
    private $email = null;
    public function setA($val = null)//defaults to default value...
    {
        $this->a = $val === null ? null : (int) $val;//cast to correct type
        return $this;
    }
    public function getA()
    {
        return $this->a;
    }
    public function setEmail($email = null)
    {
        if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL))
        {//check data here!
            $email = null;
            //or better yet:
            throw new InvalidArgumentException((string) $email.' is not a vaild email address');
        }
        $this->email = $email;
        return $this;
    }
    public function getEmail($default = null)
    {
        return $this->email ? : $default;
    }
}

このクラスの役割は明確です。セッターを介して受け取るデータを保持します。これらのセッター メソッドは生データを検証し、例外をスローしたり、正しい型にキャストしたりできます。これは、次のように使用できることを意味します。

function betterF(ArgumentsForFunc $args)
{
    $a = $args->getA();
    $email = $args->getEmail('default@email.arg');
    echo 'send ', $a, ' mails to ', $email;
}
$arg = new ArgumentsForFunc;
$arg->setA(2);
betterF($arg);//send 2 mails to default@email.arg

これで、ユーザーが のインスタンスを渡す限り、ArgumentsForFunc関数は期待どおりに動作するので安心できます。もちろん、このアプローチでは最初にもう少しコードを書く必要がありますが、デバッグの手間が大幅に軽減され、テストがはるかに簡単になります。

PS: データモデルで例外をスローします。設定中のデータが無効な場合は、至急ユーザーに通知してください。セッターが呼び出されるとすぐに例外がスローされると、バグを簡単に追跡できます。そうしない場合 (そして黙って失敗した場合)、別の場所のセッターに渡したと思っていたメール アドレスではなく、なぜあなたのgetEmail呼び出しが戻ってきたのかを突き止めようと何時間も費やすことができます。null

于 2013-09-13T12:17:28.440 に答える
1

まだ。パラメータの数を持つ関数は、1 つの引数、データ構造を持つ関数に置き換えることができます (php では、メソッドを持たず、パブリック フィールドを持つクラスです)。

function foo(FooSet $fooSet){
}

class FooSet{
 public $a = 0;
 public $b = 6;
 public $c = 2 ;
}

また、これには配列を使用しないでください。これは、「配列指向プログラミング」と呼ばれる悪い習慣です。

于 2013-09-13T12:06:21.277 に答える
1

非常に多くのパラメーターがある場合は、オブジェクトを使用して__invokeしないのはなぜですか。

class FuncClass {

    public $a = 4;
    public $b = 4;
    public $c = 4;
    public $d = 4;
    ...

    function __invoke() {
    }

}

使用する:

$func = new FuncClass();
$func->a = 3;
$func();
于 2013-09-13T12:06:49.083 に答える
0

PHP では名前付き引数を使用できません。

配列を単一のパラメーターとして使用し、実際のパラメーターを配列に入れます。

$arguments["a"]=1;
$arguments["b"]=2;
$arguments["c"]=3;


function args_test($arguments) {
   extract($arguments);
   echo $a.$b.$c;
}

args_test($arguments) は 123 を出力します。

関数の冒頭で、それらを適切なパラメーターとして使用できます

于 2013-09-13T12:07:37.270 に答える