11

個々のパラメーターではなく、キー=>値のペア (配列) を引数として使用して PHP 関数を作成するのが好きです。

たとえば、私は好きです:

function useless_func($params) {
    if (!isset($params['text'])) { $params['text'] = "default text"; }     
    if (!isset($params['text2'])) { $params['text2'] = "default text2"; }   
    if (!isset($params['text3'])) { $params['text3'] = "default text3"; }   
    echo $params['text'].$params['text2'].$params['text3'];
    return;
}

そして、私は好きではありません:

function useless_func($text = "default text", $text2 = "default text2", $text3 = "default text3") {
        echo $text.$text2.$text3;
    return;
}

私は、Wordpress のコードベースでこの方法が広範に行われているのを初めて見ました。

私が配列を好む理由:

  • 関数の引数は任意の順序で指定できます
  • コードが読みやすくなり、自己文書化が容易になる (私の意見では)
  • 関数を呼び出すときに適切な配列キーを調査する必要があるため、エラーが発生しにくい

私はこれについて同僚と話し合っていましたが、彼はそれは役に立たず、余分なコードにつながるだけであり、デフォルト値を設定するのははるかに難しいと言っています. 基本的に、彼は 3 つの点すべてで私に完全に同意しません。

洞察を提供できる可能性のある専門家からの一般的なアドバイスとガイダンスを探しています。これを行うためのより良い、またはより適切な方法は何ですか?

4

9 に答える 9

16

そうしないでください!

ほとんどの場合、すべてを配列で渡すことは悪い考えです。

  • 何を操作する必要があるかを知らずに、ユーザーが関数を使用するのを防ぎます。
  • おそらく、より正確な引数の必要性とより狭い目標を持つ関数を作成する必要がある場合に、多くのパラメーターを必要とする関数を作成できます

関数に必要なものを注入するのとは逆のようです。

関数の引数は任意の順序で指定できます

私はそのような好みはありません。その必要性がわかりません。

コードが読みやすくなり、自己文書化が容易になる (私の意見では)

ほとんどの IDE では、関数に必要なさまざまな引数が提示されます。のような関数宣言を見ればfoo(Someclass $class, array $params, $id)、関数が何を必要としているのかは非常に明確です。単一の param 引数の方が読みやすい、または自己文書化が容易であることに同意しません。

関数を呼び出すときに適切な配列キーを調査する必要があるため、エラーが発生しにくい

値がデフォルトになることを知らずに人々が配列を渡すことを許可することは、「エラーが発生しにくい」とは言えません。関数を使用する前にその関数を読むことを義務付けることは、関数が決して使用されないようにするための確実な方法です。関数を呼び出す人は、パラメーターがデフォルトで設定される値を知っており、期待する結果が表示されることを信頼するため、デフォルトと一緒に 3 つの引数が必要であると述べると、エラーが発生しにくくなります。


解決しようとしている問題が引数の数が多すぎる場合、正しい決定は、関数の依存関係を配列の背後に隠すのではなく、関数をより小さなものにリファクタリングすることです。

于 2015-08-06T18:49:09.370 に答える
14

まあ、それはちょっと便利です。ただし、常に渡されるいくつかの引数については、 のような古典的な受け渡しを使用することをお勧めしますfunction some($a1, $a2)。私は自分のコードで次のようにしています:

function getSome(SomeClass $object, array $options = array())
{
    // $object is required to be an instance of SomeClass, and there's no need to get element by key, then check if it's an object and it's an instance of SomeClass

    // Set defaults for all passed options
    $options = array_merge(array(
        'property1' => 'default1',
        'property2' => 'default2',
        ... => ...
    ), $options); 
}

ご覧のとおり、私はそのコード スタイルも気に入っていますが、core-arguments についてはクラシック スタイルを好みます。なぜなら、その方法で PHP がより多くのことを制御できるからです。

于 2012-04-17T05:40:33.787 に答える
10

すべての関数を 1 つの引数のみを受け入れるように記述し、その引数を配列にすることが良いことかどうかを尋ねていると思いますか?

あなたのコードに取り組む唯一の人なら、あなたは好きなことをすることができます。ただし、配列を介してすべての引数値を渡すことにより、特に関数名のオートコンプリートを備えた IDE を使用している場合は、関数が何をするのか、なぜ/どのように使用できるのかを理解するために、他の誰かがより懸命に努力する必要があります。など。彼らはそれを「関数シグネチャ」とは呼んでいません。

配列パラメーターは、いくつあるか分からない項目 (一連のデータ項目など) 用、または関連するオプション/設定のグループ用 (Wordpress で起こっていることかもしれません) 用に予約することをお勧めします。あなたが言及した例は?)。

配列引数への包括的アプローチを継続する場合は、少なくとも読みやすさへの影響を認識し、その問題に対処するためのいくつかの手順を実行する必要があります。

于 2012-04-17T06:04:19.890 に答える
5

これはカーゴ・カルトのプログラミングに近い。これはより読みやすく、自己文書化されていると言います。私はどのように尋ねますか?関数/メソッドの使用方法を知るには、コード自体を読み取る必要があります。署名自体から使用方法を知る方法はありません。メソッド シグネチャ ヒンティングをサポートする適切な IDE またはエディタを使用する場合、これは実際の PITA になります。さらに、PHP の型ヒント構文を使用できなくなります。

大量のパラメーター、特にオプションのパラメーターをコーディングしていることがわかった場合は、設計に問題がある可能性があることを示唆しています。他にどのように対処するかを検討してください。パラメータの一部またはすべてが関連している場合、それらは独自のクラスに属している可能性があります。

于 2012-04-17T06:34:41.590 に答える
5

あなたの同僚は正しいです。同じ機能のコードが増えるだけでなく、読みにくくなり、パフォーマンスが低下する可能性issetがあります (各パラメーターを呼び出す必要があり、配列にアクセスして値を設定する必要があるため)。

于 2012-04-17T05:59:27.537 に答える
4

を使用しても問題ありませんarray_merge()が、+演算子を使用することもできます。それは逆に機能し、まだ指定されていないデフォルト値のみを追加します。

function useless_func(array $params = array())
{
    $params += array(
        'text' => 'default text',
        'text2' => 'default text2',
        'text3' => 'default text3',
    );
}

参照:定義済みのキーに配列を渡す関数

関数の引数として配列を使用すると得られないことがいくつかあります。

  1. 型チェック (オブジェクトと配列にのみ適用されますが、有用であり、場合によっては期待できます)。
  2. よりスマートなテキスト エディターには、関数が理解できる引数を表示するコード インサイト機能があります。関数docblockに可能なキーを追加することはできますが、配列を使用するとその機能がなくなります。
  3. #2 が原因で、配列キーを間違って入力する可能性があるため、実際にはエラーが発生しやすくなります。
于 2012-09-28T06:40:29.847 に答える
1

あなたの同僚は頭がおかしいです。関数の引数として配列を渡すことはまったく問題ありません。Symfony や Doctrine を含む多くのオープン ソース アプリケーションで普及しています。私は常に 2 つの引数の規則に従ってきました。関数が 2 つ以上の引数を必要とする場合、または将来 2 つ以上の引数を使用すると思われる場合は、配列を使用します。IMO これにより、最も柔軟性が高くなり、引数が正しく渡されなかった場合に発生する可能性のある呼び出しコードの欠陥が減少します。

確かに、配列から値を推定するにはもう少し作業が必要であり、必要な要素を考慮する必要がありますが、機能の追加がはるかに簡単になり、必要なたびに関数に 13 個の引数を渡すよりもはるかに優れています。呼ばれること。

以下は、必要なパラメーターとオプションのパラメーターを表示するコードのスニペットです。

// Class will tokenize a string based on params
public static function tokenize(array $params)
{
    // Validate required elements
    if (!array_key_exists('value', $params)) {
        throw new Exception(sprintf('Invalid $value: %s', serialize($params)));
    }        

    // Localize optional elements
    $value            = $params['value'];
    $separator        = (array_key_exists('separator', $params)) ? $params['separator'] : '-';
    $urlEncode        = (array_key_exists('urlEncode', $params)) ? $params['urlEncode'] : false;
    $allowedChars     = (array_key_exists('allowedChars', $params)) ? $params['allowedChars'] : array();
    $charsToRemove    = (array_key_exists('charsToRemove', $params)) ? $params['charsToRemove'] : array();

....
于 2012-04-17T05:46:29.847 に答える
1

多くの場合、パラメーターの長いリストを置き換えるために配列を使用しましたが、うまくいきました。この投稿で、コード エディターが引数のヒントを提供できないことについて述べていることに同意します。問題は、10個の引数があり、最初の9個が空白/nullの場合、その関数を呼び出すときに扱いにくくなるということです.

また、多くの引数を必要とする関数を再設計する方法を聞くことにも興味があります。たとえば、設定されている特定の引数に基づいて SQL ステートメントを構築する関数がある場合:

function ($a1, $a2, ... $a10){

        if($a1 == "Y"){$clause_1 = " something = ".$a1." AND ";}
        ...
        if($a10 == "Y"){$clause_10 = " something_else = ".$a10." AND ";}

        $sql = "
        SELECT * FROM some_table 
        WHERE
        ".$clause_1." 
        ....
        ".$clause_10." 
        some_column = 'N'
        ";

        return $sql;
    }

PHP が、必要な型チェックを実行してパラメーターの配列を渡すのに役立つ、呼び出される関数内で使用できるネイティブ ヘルパー関数を追加することを楽しみにしています。PHP は、引数を任意の順序で渡すことができるようにする func_get_args() 関数を作成することで、これをある程度認識していました。ただし、これは値のコピーのみを渡すため、関数にオブジェクトを渡したい場合、これは問題になります。そのような関数が存在する場合、コード エディターはこれを選択して、可能な引数の詳細を提供できます。

于 2014-02-20T14:51:47.790 に答える
0

@Mike、次のように、 $params 引数をローカル変数に「抽出()」することもできます。

// Class will tokenize a string based on params
public static function tokenize(array $params)
{
    extract($params);
    // Validate required elements
    if (!isset($value)) {
        throw new Exception(sprintf('Invalid $value: %s', serialize($params)));
    }

    // Localize optional elements
    $value         = isset($value) ? $value : '';
    $separator     = isset($separator) ? $separator] : '-';
    $urlEncode     = isset($urlEncode) ? $urlEncode : false;
    $allowedChars  = isset($allowedChars) ? $allowedChars : array();
    $charsToRemove = isset($charsToRemove) ? $charsToRemove : array();

....

同じ実装ですが、短くなります。

于 2013-07-23T10:07:49.147 に答える