2009-03-25 19 views
19

名前付き関数のパラメータは、このような関数を書くとPHPでエミュレートできます。PHPで名前付き関数のパラメータをエミュレートする、良いか悪い考えですか?

function pythonic(array $kwargs) 
{ 
    extract($kwargs); 
    // .. rest of the function body 
} 

// if params are optional or default values are required 
function pythonic(array $kwargs = array('name'=>'Jon skeet')) 
{ 
    extract($kwargs); 
    // .. rest of the function body 
} 

IDEでインテリセンスを失うことは別として、このアプローチの他の可能な短所は何ですか?

編集:

セキュリティー:この場合、セキュリティーは問題にならないはずです。抽出された変数は機能範囲に限定されていますか?

答えて

33

名前付きパラメーターを渡すのに連想配列を使用することをお勧めしますが、それらを抽出せずに配列内に保持することをお勧めします。

function myFunc(array $args) { 
    echo "Hi, " . $args['name']; 
    // etc 
} 

これにはいくつかの理由があります。その関数を見ると、関数に渡された引数の1つを参照していることがはっきりとわかります。あなたがそれらを抽出し、extract()に気付かない場合、あなた(または次の男)は、この "$name"変数がどこから来たのか疑問に思ってあなたの頭を傷つけるでしょう。 を実行してもがローカル変数への引数を抽出していることが分かっていても、それはまだある程度の推測ゲームです。

第2に、他のコードがargsを上書きしないことを保証します。 $foo$barという名前の引数しか持たないことを期待して関数を書いたかもしれないので、他のコードでは例えば$baz = 8;と定義します。後で "baz"という新しいパラメータを取るように関数を拡張したいかもしれませんが、他の変数を変更するのを忘れてしまいます。引数に何が渡されても、常に0に設定されます。

(これらは配列に抽出するか、残しての方法にも同様に適用されます)あまりにも配列を使用するいくつかの利点があります:あなたは$defaultsと呼ばれる各関数の先頭に変数を設定することができます。

function myFunc (array $args) { 
    $default = array(
     "name" => "John Doe", 
     "age" => "30" 
    ); 
    // overwrite all the defaults with the arguments 
    $args = array_merge($defaults, $args); 
    // you *could* extract($args) here if you want 

    echo "Name: " . $args['name'] . ", Age: " . $args['age']; 
} 

myFunc(array("age" => 25)); // "Name: John Doe, Age: 25" 

あなたも削除することもできます対応する$default値を持たない$argsのすべてのアイテム。あなたが持っている変数を正確に知ることができます。

+2

それをうまく扱う方法。私は執筆前にあなたの答えを読んでいないことを後悔します。 – Rolf

6

は、このアプローチは、実際に2つのうちの1つが何らかの酌量すべき理由から

  1. trueの場合にのみ有益である、あなたの引数の署名が大きいです。私はちょうど6のように最大限に行く - ちょうど正しいようだが、特定の理由ではない - しかし、私は自由にこの数は任意であることを認めている。
  2. あなたの議論のすべてまたは多くはオプションで、場合によっては5番目のものまたはそのようなものの値を設定する必要があります。 someFunc(null, null, null, null, 1);

これらのいずれかが当てはまる場合は、名前付きparamsを連想配列で偽装するのが正しい実装かもしれません。抽出を避ける(または完全に避ける)のを知ることを除けば、私はすぐに他の短所を考えることができません。

と言われていますが、しばしばこれらの問題の両方は、リファクタリングによっても解決できます。

8

これを行う別の方法があります。これにより

/** 
* Constructor. 
* 
* @named string 'algorithm' 
* @named string 'mode' 
* @named string 'key' 
*/ 
public function __construct(array $parameter = array()) 
{ 
    $algorithm = 'tripledes'; 
    $mode = 'ecb'; 
    $key = null; 
    extract($parameter, EXTR_IF_EXISTS); 
    //... 
} 

設定は、デフォルトのparamsを取得するには、IDEやEXTR_IF_EXISTSでインテリセンスを失うことはありません、それだけですでに変数として存在している配列のキーを抽出することにより確保ます。

(パラメータの配列は、「名前」、インデックスなしで提供されている場合、デフォルト値が失われているのでところで、あなたが提供される例からデフォルト値を作成することは、良いではありません。)

+0

これは、クラスメソッドではない関数に対しても機能しますか? (デフォルト値:私も質問を投稿した後に) – Imran

+0

確かに、これは私のクラスのスニペットです。それは何でもできます。 – Mario

+1

'@ named'タグでintellisenseを動作させる方法を説明できますか?私は優れたインテリセンスを持つPHPStormを使用していますが、 '@ named'タグを認識することはできません。私はそれが "本当の" PHPコメントタグだとは思わないのですか? [PHPDocのタグ一覧]にはありません。(http://www.phpdoc.org/docs/latest/index.html) – Rich

2

私の経験でこのメソッドの欠点は、より多くのコードを書くことです。あなたはより多くのコードを記述する必要があります配列内のすべてのものを渡すとき

function someFunc($requiredArg, $arg1 = "default11", $arg2 = "default2") { 

この動作をシミュレートするために、および「関数のシグネチャは、」少ない「はっきりと明らかに」次のようになります。 はこのような何かを考えてみましょう。

function someFunc($requiredArg, $optionalArgs) { 
    // see other answers for good ways to simulate "named parameters" here 

PHPは、将来のリリースでは、多分関数の引数に使用可能なPascalやVBの構文のようなものを持っていることに対処するのが良いでしょう場合、私は思ったんだけど。

とにかく、私は本当に必要なときに、単一の配列にパラメータを渡します。開発中に多くの変更を加える可能性が高いパラメータセットを持つ関数のようです。これらの機能には、通常、多数のパラメータもあります。

1

他の人はあなたの他の点に答えてくれました。私はちょうどセキュリティ面についてコメントしたいと思います。

セキュリティ:抽出された変数が機能範囲に限定されているため、セキュリティはこの場合は問題ではありませんか?

はい、いいえ。あなたが書いたコードは、あなたの変数を上書きすることができます(この呼び出し後に常に変数を初期化するかどうかによって決まります)。例:このコードは、「種-の安全は」あなたがそれを呼んでいる1であるということです作る何

function pythonic(array $kwargs = array('name'=>'Jon skeet')) 
{ 
    $is_admin = check_if_is_admin(); // initialize some variable... 

    extract($kwargs); 

    // Q: what is the value of $is_admin now? 
    // A: Depends on how this function was called... 
    // hint: pythonic([ 'is_admin' => true ]) 
} 

- ので、あなたはPOSTがvarsはリダイレクトしない限り、ユーザーはもちろん、(任意のパラメータを指定することはできません。 )。

経験則として、このような魔法を避けるべきです。 extract()の行には意図しない副作用がある可能性がありますので、使用しないでください。実際には、どのアプリケーションでもextract()関数の正当な使用を考えることはできません(私はそれを自分で使ったことはないと思います)。

関連する問題