40

(この質問はコンテキストとしてPHPを使用しますが、PHPのみに限定されません。たとえば、ハッシュが組み込まれている言語も関連します)

この例(PHP)を見てみましょう:

function makeAFredUsingAssoc()
{
    return array(
        'id'=>1337,
        'height'=>137,
        'name'=>"Green Fred");
}

対:

class Fred
{
    public $id;
    public $height;
    public $name;

    public function __construct($id, $height, $name)
    {
        $this->id = $id;
        $this->height = $height;
        $this->name = $name;
    }
}

function makeAFredUsingValueObject()
{
    return new Fred(1337, 137, "Green Fred");
}

方法1はもちろん簡潔ですが、次のようなエラーが発生しやすい場合があります。

$myFred = makeAFredUsingAssoc();
return $myFred['naem']; // notice teh typo here

もちろん、それ$myFred->naemが同様にエラーにつながると主張する人もいるかもしれませんが、それは真実です。しかし、正式なクラスを持つことは私にとってより厳格に感じますが、私はそれを本当に正当化することはできません。

それぞれのアプローチを使用することの長所/短所は何であり、人々はいつどのアプローチを使用する必要がありますか?

4

11 に答える 11

32

表面的には、2つのアプローチは同等です。ただし、クラスを使用すると、カプセル化、継承など、標準のOOの利点のほとんどを利用できます。

また、次の例を見てください。

$arr['naem'] = 'John';

は完全に有効であり、見つけるのが難しいバグである可能性があります。

一方で、

$class->setNaem('John');

動作しません。

于 2010-01-13T13:41:46.737 に答える
30

このような単純なクラス:

class PersonalData {
    protected $firstname;
    protected $lastname;

    // Getters/setters here
}

アレイに比べていくつかの利点があります。

  1. いくつかのタイプミスをする可能性はありません。エラーをスロー$data['firtsname'] = 'Chris';しながら動作します。$data->setFirtsname('Chris');
  2. タイプヒント:PHP配列にはすべて(何も含まない)を含めることができますが、明確に定義されたクラスには指定されたデータのみが含まれます。

    public function doSth(array $personalData) {
        $this->doSthElse($personalData['firstname']); // What if "firstname" index doesn't exist?
    }
    
    
    public function doSth(PersonalData $personalData) {
        // I am guaranteed that following method exists. 
        // In worst case it will return NULL or some default value
        $this->doSthElse($personalData->getFirstname());
    }
    
  3. 検証やロギングなどの設定/取得操作の前に、いくつかのコードを追加できます。

    public function setFirstname($firstname) {
        if (/* doesn't match "firstname" regular expression */) {
            throw new InvalidArgumentException('blah blah blah');
        }
    
    
    
    if (/* in debbug mode */) {
        log('Firstname set to: ' . $firstname);
    }
    
    
    $this->firstname = $firstname;
    
    }
  4. 継承、ポリモーフィズム、型ヒント、カプセル化など、OOPのすべての利点を利用できます...
  5. 前に述べたように、すべての「構造体」はCountableSerializableまたはIteratorインターフェイスの実装を提供する基本クラスから継承できるため、構造体はforeachループなどを使用できます。
  6. IDEのサポート。

唯一の欠点は速度だと思われます。アレイの作成とその操作はより高速です。ただし、多くの場合、CPU時間はプログラマー時間よりもはるかに安いことは誰もが知っています。;)

于 2010-10-05T10:44:56.417 に答える
8

しばらく考えた後、これが私自身の答えです。

配列よりも値オブジェクトを優先することについての主なことは、明快さです。

この関数について考えてみましょう。

// Yes, you can specify parameter types in PHP
function MagicFunction(Fred $fred)
{
    // ...
}

function MagicFunction(array $fred)
{
}

意図はより明確です。関数の作成者は、自分の要件を適用できます。

さらに重要なことに、ユーザーとして、有効なフレッドを構成するものを簡単に調べることができます。私はただ開いFred.phpてその内部を発見する必要があります。

発信者と着信者の間には契約があります。値オブジェクトを使用すると、このコントラクトは構文チェックされたコードとして記述できます。

class Fred
{
    public $name;
    // ...
}

配列を使用した場合、ユーザーがコメントまたはドキュメントを読んでくれることを期待できます。

// IMPORTANT! You need to specify 'name' and 'age'
function MagicFunction(array $fred)
{
}
于 2010-10-05T12:17:02.657 に答える
6

ユースケースに応じて、またはを使用する場合があります。このクラスの利点は、タイプのように使用でき、メソッドまたは任意のイントロスペクションメソッドでタイプヒントを使用できることです。クエリなどからランダムなデータセットを渡したいだけの場合は、配列を使用する可能性があります。ですから、フレッドが私のモデルで特別な意味を持っている限り、私はクラスを使用すると思います。

補足:
ValueObjectsは不変であると想定されています。少なくとも、ドメイン駆動設計でエリック・エバンスの定義を参照している場合。FowlerのPoEAでは、ValueObjectsは必ずしも不変である必要はありませんが(推奨されていますが)、アイデンティティを持っている必要はありません。これは明らかにFredの場合です。

于 2010-01-13T13:58:41.817 に答える
3

この質問をあなたに提起させてください:

$myFred['naem']タイプミスを好きにすることとタイプミスを好きにすることの違いは何$myFred->naemですか?同じ問題が両方の場合にまだ存在し、両方ともエラーになります。

私はプログラミングするときにKISSを使用するのが好きです(シンプルで愚かにしてください)。

  • メソッドからクエリのサブセットを返すだけの場合は、配列を返すだけです。
  • いずれかのクラスでデータをpublic/private / static / protected変数として保存する場合は、stdClassとして保存するのが最適です。
  • Fred後でこれを別のクラスメソッドに渡す場合は、クラスの厳密な型指定をお勧めします。public function acceptsClass(Fred $fredObj)

戻り値として使用する場合は、配列ではなく標準クラスを簡単に作成できます。この場合、厳密な入力についてはあまり気にする必要はありません。

$class = new stdClass();
$class->param = 'value';
$class->param2 = 'value2';
return $class;
于 2010-01-13T13:43:31.190 に答える
2

ハッシュの長所:設計時に不明な名前と値の組み合わせを処理できます。

于 2010-01-13T13:45:15.510 に答える
1

戻り値がアプリケーション内のエンティティを表す場合、これがOOPの目的であるため、オブジェクトを使用する必要があります。無関係な値のグループを返したいだけの場合は、それほど明確ではありません。ただし、それがパブリックAPIの一部である場合でも、宣言されたクラスが最善の方法です。

于 2010-01-13T13:40:38.343 に答える
1

正直なところ、私は両方が好きです。

  • ハッシュ配列はオブジェクトを作成するよりもはるかに高速であり、時は金なりです!
  • しかし、JSONはハッシュ配列(OOP OCDに少し似ているようです)を好みません。
  • たぶん、複数の人がいるプロジェクトの場合、明確に定義されたクラスの方が良いでしょう。
  • ハッシュ配列は、すべてのシナリオで確認するのは困難ですが、より多くのCPU時間とメモリ(オブジェクトには事前定義された量があります)を必要とする場合があります。

しかし、本当にひどいのは、どれを使いすぎるかを考えることです。私が言ったように、JSONはハッシュが好きではありません。おっと、私は配列を使用しました。今、数千行のコードを変更する必要があります。

私はそれが好きではありませんが、クラスがより安全な方法のようです。

于 2010-10-05T10:20:59.787 に答える
1

適切な値オブジェクトの利点は、実際に無効なオブジェクトを作成する方法や、存在する値オブジェクトを変更する方法(整合性と「不変性」)がないことです。ゲッターと型ヒントパラメーターだけで、コンパイル可能なコードでそれを台無しにする方法はありません。これは、順応性のある配列で明らかに簡単に行うことができます。

または、パブリックコンストラクターで検証して例外をスローすることもできますが、これにより、より穏やかなファクトリメソッドが提供されます。

class Color
{
    public static function create($name, $rgb) {
        // validate both
        if ($bothValid) {
            return new self($name, $rgb);
        } else {
            return false;
        }
    }
    public function getName() { return $this->_name; }
    public function getRgb() { return $this->_rgb; }

    protected function __construct($name, $rgb)
    {
        $this->_name = $name;
        $this->_rgb = $rgb;
    }
    protected $_name;
    protected $_rgb;
}
于 2011-04-16T03:41:34.740 に答える
1

私は10年以上OOP言語を扱ってきました。オブジェクトの動作を理解していれば、きっと気に入るはずです。継承、ポリモーフィズム、カプセル化、オーバーロードは、OOPの主な利点です。一方、PHPについて話すときは、PHPがフル機能のオブジェクト指向言語ではないことを考慮する必要があります。たとえば、メソッドのオーバーロードやコンストラクターのオーバーロードを使用することはできません(簡単です)。

PHPの連想配列は非常に優れた機能ですが、phpエンタープライズアプリケーションに害を及ぼすと思います。あなたがコードを書くとき、あなたはクリーンでメンテナンス可能なアプリケーションを手に入れたいです。

連想配列で失うもう1つの考えは、インテリセンスを使用できないということです。

したがって、よりクリーンで保守しやすいコードを記述したい場合は、提供されたときにOOP機能を使用する必要があると思います。

于 2012-01-29T19:02:10.450 に答える
0

2番目の例のように、ハードコードされたプロパティを使用することをお勧めします。期待されるクラス構造(およびクラスで可能なすべてのプロパティ)をより明確に定義しているように感じます。要約すると、常に同じキー名を使用することを覚えているという最初の例とは対照的です。2つ目では、いつでも戻ってクラスを確認し、ファイルの先頭を確認するだけでプロパティを把握できます。

2番目のもので何か間違ったことをしていることがよくわかります。しようとするecho $this->doesntExistとエラーが発生しますが、しようとするとエラーは発生しecho array['doesntExist']ません。

于 2010-01-13T13:40:10.713 に答える