web-dev-qa-db-ja.com

PHPでクラスメンバーを初期化するためのベストプラクティス

私のコンストラクタには次のようなコードがたくさんあります:-

function __construct($params) {

    $this->property = isset($params['property']) ? $params['property'] : default_val;

}

プロパティ定義でデフォルト値を指定するよりも、これを行う方が良いですか?つまり、public $property = default_val?時々、デフォルト値のロジックがあり、いくつかのデフォルト値は他のプロパティから取得されるため、コンストラクターでこれを行っていました。

デフォルト値のすべてのロジックが分離されるようにセッターを使用する必要がありますか?

10
rgvcorley

私は以前、このような哲学的な議論を私自身と持っていました。私はこれが意見に基づく答えであることを理解していますが、私はほとんどの場合ここに立っています:

質問に答えるのに役立つかもしれないと私が思う1つのことは、$ paramsを渡すことです。これには、属性/配列のメンバーが設定されている場合と設定されていない場合があります。

長年にわたって私はこの結論に達しました:

配列を渡さないでください。

どうして?まあ、オプションの渡された引数に対してセンチネル値を設定または定義する方法はありません。

つまり、指定したコードでは、次のようなことはできません。

function __construct($arg1 = NULL, $arg2 = DEFAULT_VAL) {

    $this->arg1 = $arg1;

    $this->arg2 = $arg2;

}

$ arg1と$ arg2はオプションの引数です-渡されない場合、それぞれNULLとDEFAULT_VALがあります-明示的にチェックする必要はありません。

多分これは一種の恣意的なようです。

私はあなたが達成しようとしていることを理解していると思います-たくさんの議論とは対照的に単一の参照を渡すことです。これは私に私の次の結論をもたらします:

「アトミック」変数(文字列、整数、リテラル)を渡さない場合は、オブジェクトを渡します。

オブジェクトの受け渡しは参照によって行われるため、ここにはパフォーマンス上の利点があります(PHP内では配列はほぼ同じだと思います)。

だからあなたは次のようなことをするかもしれません:

function __construct(MyAwesomeObject $oArg) {

        $this->oArg = $oArg;

    }

渡されたオブジェクト引数は、デフォルト値自体を使用している可能性がありますが、「property1」、「property2」を持っていることが保証されます。

さらに、ここではヒントを入力でき、適切なIDEはコード補完も正しく自動提案します。

しかし、ニワトリとエッグの問題が発生していることにすぐに気づきます。ある時点で構築する必要がある、渡されたオブジェクト引数を使用してオブジェクトを構築しています。

これはどこに私たちを残すのでしょうか?まあ、私は結局、すべてのクラスが「原子」変数(文字列、浮動小数点数、倍精度浮動小数点数、整数、あなたが私のポイントを得るリソース)に蒸留され、より良い用語がないために、私は試す傾向があるという結論に達しましたこれらの変数型またはオブジェクトを使用してすべてのクラスを構築します-配列は作成しません。

だから私はあなたの質問に答えましたか?おそらく正確ではない。しかし、私は多少様式的にではありますが、役に立つものを示してくれれば幸いです。コードは少しすっきりとして、読みやすく、コストも安いと思います。

さて、これはあなたの入力を無害化すべきではないと言っているのではありません。それは完全に別の議論です。

お役に立てれば。

8
ekeyser

配列をコンストラクターに渡さないようにする傾向がありますが、(構成ファイルから値を読み取るクラスの場合など)着信配列値を処理する必要がある場合があります。

このような場合、PHPの配列関数を利用して、自分が操作していると思うものを正確に操作できるようにします。

_public function import( array $incoming )
{
  $defaults = array(
      'foo' => DEFAULT_FOO
    , 'bar' => DEFAULT_BAR
    ...
  );

  $values = array_merge($defaults, array_intersect_key($incoming, $defaults));

  ...
}
_

その最後の行ではarray_merge()を使用して、_$defaults_の値を_$incoming_の対応する値で上書きしています。また、array_intersect_key()を使用して、結果の配列にクラス/メソッドが処理方法を知らない余分なキーが含まれていないことを確認します。

3
user34530