1

次のように、PHP でオプションのパラメーターの型を確認しています。

/**
 * Get players in the team using limit and
 * offset.
 *
 *
 * @param TeamInterface $participant
 * @param int $limit
 * @param int $offset
 * @throws \InvalidArgumentException
 * @return Players of a team
 */
public function getPlayers(TeamInterface $team, $limit = null, $offset = null)
{
    if (func_num_args() === 2 && !is_int($limit) ){
        throw new \InvalidArgumentException(sprintf('"Limit" should be of int type, "%s" given respectively.', gettype($limit)));
    }
    if (func_num_args() === 3 && (!is_int($limit) || !is_int($offset))){
        throw new \InvalidArgumentException(sprintf('"Limit" and "Offset" should be of int type, "%s" and "%s" given respectively.', gettype($limit), gettype($offset)));
    }
//.....

}

これは機能しますが、これには 2 つの主な問題があります。

1/ 同じ型の 4/5 オプション パラメータの型をチェックする必要がある場合int、コードが不必要に長くなります。このコードをより保守しやすくする方法はありますか? (おそらく、 と の両方の同じタイプをチェックするために 1 つのステートメントのみを使用しifます)$limit$offset

2/getPlayers($team, 2, null)例外をスローします。null関数が実際にここで値を処理できることを知っていれば、これで問題ありませんか?

4

5 に答える 5

2

引数の配列を使用して for ループを実行できます。何かのようなもの:

$args = func_get_args();
for ($i = 1; $i < 4; $i++) {
    if ($args[$i] !== null and !is_int($args[$i])) {
        throw ...
    }
}

もちろん、チェックする必要がある引数の数に基づいて for 条件を調整します。

または...

$args = func_get_args();
// skip first
array_shift($args);
foreach ($args as $arg) {
    if ($arg !== null and !is_int($arg)) {
        throw ...
    }
}
于 2013-02-27T03:40:39.233 に答える
1

1)の場合、各変数を個別にチェックし、それぞれに例外をスローします。

   if (!is_int($limit)){
        //Throw
    }
    if (!is_int($offset))){
        //Throw
    }

これでも、変数ごとにifステートメントが必要ですが、少し冗長ではありません。

2)null値が許可されている場合は、チェックを次のように変更できます。

if ($offset && !is_int($offset))){
    //Throw
}

最後に、チェックすることはお勧めしませんfunc_num_args()。サンプルコードでは、引数が多すぎる関数を呼び出すと、検証がバイパスされます。

于 2013-02-27T03:41:53.060 に答える
1

個人的には、関数ごとに引数を 1 つだけ持つことを好みます (関数が非常に単純でない限り)。たとえば、関数は を取り$request、 data のツリーを返します$response。後でループして拡張するのが少し簡単になります。

function dostuff( $request ) {

   $team   = @$request['team'];
   $limit  = @$request['limit'];
   $offset = @$request['offset'];

   // ...
   return $response;
}

次に、検証のために、次のように関数の上部に一連のルールを記述できます

   // define validation rules
   $rules = array( 'required' => array('team'),      
                   'depends' => array('offset' => 'limit'),      
                   'types' => array('offset' => 'int', 'limit' => 'int' ),
            );

そして、すべてのエラー チェックを 1 回の呼び出しで集中化します。

   // can throw exception
   argcheck( array( 'request' => $request, 'rules' => $rules ) );

これには最適化が必要な場合がありますが、関数の複雑さが増すにつれて、一般的なアプローチは肥大化を抑えるのに役立ちます。

于 2013-02-27T03:46:22.007 に答える
1

PHP には、スカラーの型ヒントがまだありません。

再設計

関数で多くのオプションの引数を取り始めると、コードの匂いがします。何かがおかしいです。現れるのを待っているオブジェクトがあります。

オプションのパラメータをすべて Object として構築し、validate メソッドを設定します。

GameParameters オブジェクトが必要で、validate メソッドが必要だと思います。

getPlayers($gameParameters) {
}

パラメータの検証をそのオブジェクトに移動して、各セッターに組み込むか、包括的な validate() 関数を使用します。

組み合わせ問題

チェックの急増に関する限り、エラーの配列を構築し、エラーがある場合はそれをスローします。これは、再設計の有無にかかわらず実行できます。

if ($limit != null && !is_int($limit){
  #add to the errors array      
}

if ($offset != null && !is_int($offset){
  #add to the errors array      
}

if (errors) {
  throw new \InvalidArgumentException(sprintf('"Limit" and "Offset" should be of int type, "%s" and "%s" given respectively.', gettype($limit), gettype($offset)));
}
于 2013-02-27T03:47:26.523 に答える
0

switch を使用して、特定の機能をコーディングします。

switch(gettype($limit)) {
    case "integer":
        //do other processing
    break;
}

そのようにコードを脆弱なままにしておくことはできません。脆弱性を克服するための安全なソリューションについて。このようなセーフ リストを作成します。

public function getPlayers(TeamInterface $team, $limit = null, $offset = null) {
    $safelist = array("var1" => "TeamInterface", "var2" => "integer", "var3" => "integer");
    $args = function_get_args();
    $status = true;
    foreach($args as $key => $var) {
        if(gettype($var)!=$safelist["var".$key]) {
             $status = false;
             break;
        }
    }
    if(!$status) break;

    //...........
}
于 2013-02-27T03:34:54.967 に答える