PHP:いつ配列を使用し、ほとんどのデータを保存するコード構成にオブジェクトを使用するのですか?


37

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

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

{cost、name、part_number、item_count}で構成されるアイテムタイプがあるとします。プログラムでは、そのようなアイテムタイプをいくつか表示する必要があります。ここでは、各アイテムタイプを保持する外部コンテナとして配列を使用することにします。[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なる可能性があります。たとえば、を削除すると、変更するコード行が少なくなります。しかし、より高いレベルのオブジェクト指向機能が関係するため、変更自体は配列メソッドと比較して高い認知負荷を必要とする場合があります。

質問

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


2
オブジェクトに配列をキャストすることにより、軽量オブジェクトを取得できることに注意してください(object)['foo'=>'bar']。結果の値はclassを持ちStdClass、全体でJSONエンコードされjson_encode()、プロパティは配列インデックスと同じくらい簡単に名前を変更できます(変数を介して間接的にアクセスされる場合、これは必ずしも簡単ではありません)。ただし、このような値にはさまざまな操作があります。たとえば、配列共用体があるためオブジェクト共用体はなく、array_*()関数を直接使用することはできません。
outis

3
:あなたは3つのオプションがあり1: array2: User-defined Class3: stdClass。速度の面でのパフォーマンスはarray、aとUser-defined class(a などItemType)を比較する場合とほぼ同じですが、定義されたclassesはarrays を使用するよりも少ないメモリを使用する傾向があります。stdClass一方、3つのオプションの中で最も遅く、またほとんどのメモリを使用します。
アンディ

回答:


33

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

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

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

  2. このデータを複数のPHP関数に渡しますか?

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

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

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

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

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

最終的には、コードのスケーリングニーズを考慮し、構造化配列が迅速な修正になる可能性があることを考慮しますが、クラスははるかに回復力がありスケーラブルなソリューションです。

また、次のことも考慮してjson_data()ください。クラスがあり、JSONに出力する場合、クラス内のデータの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());

の要素は変更しないmy_lineitemsため、特に変数はオブジェクト自体ではなくオブジェクトの識別子のみを保持するため、参照によって取得する必要はありません。php.net/manual/en/language.oop5.references.php
Chinoto Vokro

同意した。これは、何らかの理由で参照が必要なはるかに大きなアプリケーションのスニペットだと思います
ジョシュ

2

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

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'
}
*/

この質問は、既存の受け入れられた答えに何を追加しますか?
-esoterik

@esoterikネスト。json_encode(['order'=>$o]);存在する受け入れられた答えは空白です:{"order":{}}。必ず使用できます:$o->forJSON()すべてのレベルのすべてのオブジェクトで毎回、しかし本当に良いデザインではありません。すべてのため、あなたのような書き込み気にいらに必要な時間: $items_json = array(); foreach($this->my_lineitems as $item) $items_json[] = $item->forJSON();
エル」
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.