web-dev-qa-db-ja.com

PHP:いつ配列を使用し、ほとんどの場合データを格納するコード構造にオブジェクトを使用するのはいつですか?

PHPは混合パラダイム言語であり、配列などの非オブジェクトデータ型を使用して返すことができます。特定の状況で使用するプログラミング構成を決定する際に、配列とオブジェクトの選択に関するガイドラインを明確にするために、質問を投げかけます。

これは、PHP言語構成を使用してデータをエンコードする方法、およびデータ受け渡しの目的(つまり、サービス指向アーキテクチャーまたはWebサービス)で1つの方法が他の方法よりも選択される可能性が高い場合)に関する質問です。

{cost、name、part_number、item_count}で構成されるアイテムタイプがあるとします。プログラムは、このようないくつかの項目タイプの表示を要求します。ここでは、配列を外部コンテナーとして使用して各項目タイプを保持することにします。 [OOパラダイム)にPHPのArrayObjectを使用することもできますが、私の質問はそれではありません (外部)配列]。私の質問は、項目タイプのデータをエンコードする方法と、どのパラダイムを使用するかについてです。PHPを使用すると、PHP Native ArraysまたはPHP Objectsを使用できます。

このようなデータは、次の2つの方法でエンコードできます。

//PHP's associative arrays:
$ret = array(
    0 => array(
        'cost' => 10.00, 
        'name' => 'item1',
        'part_number' => 'zyz-100', 
        'item_count' => 15
        ),
    1 => array(
        'cost' => 34.00, 
        'name' => 'item2', 
        'part_number' => 'abc-230', 
        'item_count' => 42
        ),
  );

//here ItemType is encapsulated into an object
$ret = array(
  0 => new ItemType(10.00, 'item1', 'zyz-100', 15),
  1 => new ItemType(34.00, 'item2', 'abc-230', 42),
);

class ItemType
{
    private $price;
    private $name;
    private $partNumber;
    private $itemCount;

    function __construct($price, $name, $partNumber, $itemCount) {..}
}

私が考えていること

配列のエンコードは軽量で、JSONに対応していますが、扱いが簡単です。連想配列キーの1つにスペルミスがあると、エラーの検出が困難になる可能性があります。しかし、気まぐれで変更するのも簡単です。 item_countを保存したくない場合は、テキスト処理ソフトウェアを使用して、配列内のすべてのitem_countインスタンスを簡単に削除し、それに応じてそれを使用する他の関数を更新できます。それはより退屈なプロセスかもしれませんが、それは簡単です。

オブジェクト指向のエンコーディングは、IDEおよびPHP言語機能を呼び出し、事前にエラーを簡単にキャッチできるようにしますが、最初にプログラミングおよびコード化することは困難です。 。オブジェクトについて少し考え、前に考えなければならないので、私はもっと難しいと言います。そして、OOコーディングは、配列構造をタイプするよりも、認知的負荷が少しかかります。それがコード化されると、たとえば、item_countを削除することで、コードの行を変更する必要が少なくなるという意味で、一部の変更は実装が容易になる可能性があります。上位レベルOO施設が関与しています。

質問

場合によっては、データの操作を実行する必要がある場合のように、それが明らかな場合があります。しかし、場合によっては、「アイテムタイプ」データの数行を格納する必要があるだけで、配列を使用するかオブジェクトを構築するかを決定するときに頼る明確なガイドラインや考慮事項がありません。コインを投げて選ぶだけのようです。ここはそうですか?

37
Dennis

これを見る方法は、後でデータをどう処理するかによって異なります。いくつかの簡単なチェックに基づいて、2つのデータ構造のどちらが適しているかを判断できます。

  1. このデータにはロジックが関連付けられていますか?

    たとえば、_$price_は整数のセントとして格納されるので、価格が$ 9.99の製品は_price = 999_ではなく_price = 9.99_になりますか? (おそらく、はい)またはpartNumberは特定の正規表現に一致する必要がありますか?または、itemCountが在庫にあるかどうかを簡単に確認できるようにする必要がありますか? これらの機能を将来的に実行する必要がありますか?実行する場合は、今すぐクラスを作成することをお勧めします。これは、データ構造に組み込まれた制約とロジックを定義できることを意味します:_private $myPrice_は_999_に設定されますが、$item->getPriceString()は_$9.99_および$item->inStock()を返しますアプリケーションで呼び出すことができます。

  2. このデータを複数に渡すつもりですかPHP functions?

    その場合は、クラスを使用します。このデータを一度生成して変換を実行する場合、またはJSONデータとして別のアプリケーション(JavaScriptなど)に送信する場合は、配列の方が簡単です。ただし、このデータをパラメーターとして受け入れるPHP関数が3つ以上ある場合は、クラスを使用します。それ以外の場合は、someFunction(MyProductClass $product) {を定義することができます。関数は入力として期待します。コードをスケールアウトして関数を増やすと、各関数が受け入れるデータのタイプを簡単に知ることができます。someFunction($someArrayData) {を確認することはそれほど明確ではありません。また、これは型の一貫性を強制し、(あなたが言ったように)配列の柔軟な構造が後で開発の痛みを引き起こす可能性があることを意味します

  3. ライブラリまたは共有コードベースを構築していますか?

    もしそうなら、クラスを使用してください!ライブラリを使用している新しい開発者、または社内でコードを使用したことがない別の開発者について考えてください。彼らがクラス定義を見て、そのクラスが何をするかを理解すること、または特定のクラスのオブジェクトを受け入れるライブラリ内のいくつかの関数を見ることが、彼らが生成する必要がある構造を推測するよりもはるかに簡単になります配列の数。また、これは#1のデータ整合性の問題に触れています。ライブラリまたは共有コードベースを開発している場合は、ユーザーに優しくしてください。データ整合性を適用し、データの設計でエラーが発生しないようにするクラスをユーザーに提供します。 。

  4. これはアプリケーションの小さな部分ですか、それとも単なるデータの変換ですか?上記のいずれにも当てはまりませんか?

    クラスは多すぎるかもしれません。それがあなたに合い、あなたがそれをより簡単に見つけたなら、配列を使用してください。上記のように、JSON、YAML、XMLなどとして送信する構造化データを生成するだけの場合は、必要がない限り、クラスを気にしないでください。大きなモジュールで小さなモジュールを作成していて、他のモジュールやチームがコードとやり取りする必要がない場合は、配列で十分です。

結局のところ、コードのスケーリングの必要性を考慮してくださいであり、構造化配列は迅速な修正である可能性があることを考慮してください。

また、次の点も考慮してください。クラスがあり、JSONに出力する場合は、クラスのjson_data()メソッドを定義して、JSONで変換可能なデータの配列を返すことができない理由はありません。クラスで。これは、クラスデータをJSONとして送信する必要があるPHPアプリケーションで行ったものです。例として:

_class Order {
    private $my_total;
    private $my_lineitems;

    public function getItems() { return $this->my_lineitems; }
    public function addItem(Product $p) { $this->my_lineitems[] = $p; }
    public function getTotal() { return $this->my_total; }

    public function forJSON() {
        $items_json = array();
        foreach($this->my_lineitems as $item) $items_json[] = $item->forJSON();
        return array(
            'total' => $this->getTotal(),
            'items' => $items_json
        );
    }
}

$o = new Order();
// do some stuff with it
$json = json_encode($o->forJSON());
_
33
Josh

JsonSerializableインターフェイスを使用してjson構造を実装し、ネストされた配列/クラスを任意の方法で使用できます。 Classは、get/set操作が高速で、デバッグが容易です。 Arrayでは、宣言は必要ありません。

class Order implements \JsonSerializable{
    private $my_total;
    private $my_lineitems;

    public function getItems() { return $this->my_lineitems; }
    public function addItem(Product $p) { $this->my_lineitems[] = $p; }
    public function getTotal() { return $this->my_total; }

    public function jsonSerialize(){
        return [
            'total'=>$this->my_total,
            'products'=>$this->my_lineitems;
        ];
    }
}

class Product implements \JsonSerializable{
    private $name;
    private $price;

    public function jsonSerialize(){ 
        return [
            'name'=>$this->name, 
            'price'=>$this->price
        ];
    }
}

$order = new Order();
$order->addProduct(new Product('Product1', 15));
$order->addProduct(new Product('Product2', 35));
$order->addProduct(new Product('Product3', 42));
$json = json_encode(['order'=>$order, 'username'=>'Eughen']);
/*
json = {
    order: {
        total: 92, 
        products: [
            {
                name: 'Product1',
                price: 15
            }, 
            {
                name: 'Product2',
                price: 35
            },
            {
                name: 'Product3',
                price: 42
            }
        ]
    }, 
    username: 'Eughen'
}
*/
2
El'