PHP: Wann werden Arrays verwendet und wann werden Objekte für Code-Konstrukte verwendet, die hauptsächlich Daten speichern?


37

PHP ist eine gemischte Paradigmasprache, mit der Datentypen, die keine Objekte sind, wie z. B. Arrays, verwendet und zurückgegeben werden können. Ich stelle eine Frage, um zu versuchen, einige Richtlinien für die Auswahl von Arrays gegenüber Objekten zu klären, wenn ich mich für ein Programmierkonstrukt in einer bestimmten Situation entscheide.

Dies ist wirklich eine Frage zu Möglichkeiten, Daten mithilfe von PHP-Sprachkonstrukten zu codieren, und zu der Frage, ob eine Möglichkeit für die Datenübermittlung (d. H. Serviceorientierte Architektur oder Webservices) wahrscheinlicher als eine andere gewählt werden soll.

Beispiel

Angenommen, Sie haben einen Artikeltyp bestehend aus {cost, name, part_number, item_count}. Ihr Programm fordert die Anzeige mehrerer solcher Elementtypen an, in denen Sie ein Array als äußeren Container für die einzelnen Elementtypen verwenden möchten. [Sie können auch PHP ArrayObjectfür das OO-Paradigma verwenden, aber meine Frage bezieht sich nicht auf dieses (äußere) Array]. Meine Frage ist, wie die Artikeltypdaten zu codieren sind und welches Paradigma zu verwenden ist. Mit PHP können Sie PHP Native Arraysoder verwenden PHP Objects.

Ich kann solche Daten auf zwei Arten kodieren:

//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
        ),
  );

vs

//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) {..}
}

Was ich denke

Die Array-Codierung ist leicht und JSON-fähiger, kann jedoch leichter durcheinander gebracht werden. Wenn Sie einen der assoziativen Array-Schlüssel falsch schreiben, liegt möglicherweise ein Fehler vor, der schwerer abzufangen ist. Aber es ist auch einfacher, aus einer Laune heraus zu wechseln. Angenommen, ich möchte nicht item_countmehr speichern , ich kann jede Textverarbeitungssoftware verwenden, um auf einfache Weise alle item_countInstanzen im Array zu entfernen und dann andere Funktionen zu aktualisieren, die sie entsprechend verwenden. Es mag ein langwieriger Prozess sein, aber es ist einfach.

Die objektorientierte Codierung ruft die IDE- und PHP-Sprachfunktionen auf und erleichtert das Abfangen von Fehlern im Voraus, ist jedoch in erster Linie schwieriger zu programmieren und zu codieren. Ich sage es härter, weil Sie ein wenig über Ihre Objekte nachdenken und vorausdenken müssen und die OO-Codierung eine etwas höhere kognitive Belastung erfordert als das Schreiben von Array-Strukturen. Das heißt, wenn es einmal codiert ist, können einige Änderungen in gewissem Sinne einfacher implementiert werden, da zum Entfernen item_countbeispielsweise weniger Codezeilen erforderlich sind. Änderungen selbst können jedoch im Vergleich zur Array-Methode noch eine höhere kognitive Belastung erfordern, da übergeordnete OO-Einrichtungen beteiligt sind.

Frage

In einigen Fällen ist es klar, wie in Fällen, in denen ich Manipulationen an den Daten vornehmen muss. In einigen Fällen, in denen ich nur ein paar Zeilen mit "Artikeltyp" -Daten speichern muss, kann ich mich nicht auf klare Richtlinien oder Überlegungen stützen, um zu entscheiden, ob Arrays verwendet oder Objekte erstellt werden sollen. Es scheint, als könnte ich einfach eine Münze werfen und eine auswählen. Ist das hier der Fall?


2
Beachten Sie ein leichtes Objekt durch ein Array Gießen auf ein Objekt bekommen: (object)['foo'=>'bar']. Der resultierende Wert hat die Klasse StdClass, wird in seiner Gesamtheit von JSON-codiert json_encode()und Eigenschaften können genauso einfach umbenannt werden wie Array-Indizes (was nicht immer so einfach ist, wenn indirekt über eine Variable darauf zugegriffen wird). Es gibt jedoch unterschiedliche Operationen für solche Werte. Sie haben beispielsweise keine Objekt-Unions, wie Sie Array-Unions haben, und Sie können die array_*()Funktionen nicht direkt verwenden .
8.

3
Sie haben 3 Optionen: 1: array , 2: User-defined Class , 3: stdClass . Die Leistung in Bezug auf die Geschwindigkeit ist im Vergleich arraymit a User-defined class(wie z. B. Ihrer ItemType) ziemlich gleich , aber definierte classes belegen tendenziell weniger Speicher als arrays. stdClassAuf der anderen Seite ist die langsamste der drei Optionen und verwendet auch den meisten Speicher.
Andy

Antworten:


33

Wie ich das sehe, hängt davon ab, was Sie danach mit den Daten machen wollen. Anhand einiger einfacher Überprüfungen können Sie feststellen, welche der beiden Datenstrukturen für Sie besser ist:

  1. Haben diese Daten eine Logik?

    Wird zum Beispiel $priceeine ganze Zahl von Cent gespeichert, so hätte ein Produkt mit einem Preis von 9,99 USD price = 999und nicht price = 9.99? (Wahrscheinlich ja) Oder muss partNumbereine bestimmte Regex übereinstimmen? Oder müssen Sie in der Lage sein, leicht zu überprüfen, ob das itemCountin Ihrem Inventar verfügbar ist? Müssen Sie diese Funktionen in Zukunft ausführen? In diesem Fall ist es am besten, jetzt eine Klasse zu erstellen. Dies bedeutet, dass Sie Integritätsbedingungen und Logik definieren können, die in die Datenstruktur integriert sind: private $myPriceist auf gesetzt, gibt 999aber $item->getPriceString()zurück $9.99und $item->inStock()steht zum Aufrufen in Ihrer Anwendung zur Verfügung.

  2. Übergeben Sie diese Daten an mehrere PHP-Funktionen?

    Wenn ja, dann benutze eine Klasse. Wenn Sie diese Daten einmal generieren, um einige Transformationen durchzuführen, oder um sie einfach als JSON-Daten an eine andere Anwendung (JavaScript oder auf andere Weise) zu senden, ist ein Array die einfachere Wahl. Wenn Sie jedoch mehr als zwei PHP-Funktionen haben, die diese Daten als Parameter akzeptieren, verwenden Sie eine Klasse. Wenn nichts anderes, können Sie damit definieren someFunction(MyProductClass $product) {und es ist sehr klar, was Ihre Funktionen als Eingabe erwarten. Wenn Sie Ihren Code skalieren und über mehr Funktionen verfügen, ist es viel einfacher zu wissen, welche Art von Daten jede Funktion akzeptiert. Sehen someFunction($someArrayData) {ist bei weitem nicht so klar. Dies erzwingt auch keine Typenkonsistenz und bedeutet, dass (wie Sie sagten) die flexible Struktur des Arrays später zu Entwicklungsproblemen führen kann

  3. Bauen Sie eine Bibliothek oder eine gemeinsam genutzte Codebasis auf?

    Wenn ja, benutze eine Klasse! Denken Sie an einen neuen Entwickler, der Ihre Bibliothek verwendet, oder an einen anderen Entwickler in der Firma, der Ihren Code noch nie zuvor verwendet hat. Es ist für sie viel einfacher, sich eine Klassendefinition anzusehen und zu verstehen, was diese Klasse tut, oder eine Reihe von Funktionen in Ihrer Bibliothek zu sehen, die Objekte einer bestimmten Klasse akzeptieren, als zu erraten, welche Struktur sie in einer Klasse generieren müssen Anzahl der Arrays. Dies betrifft auch die Probleme mit der Datenkonsistenz bei Nummer 1: Wenn Sie eine Bibliothek oder eine gemeinsam genutzte Codebasis entwickeln, seien Sie nett zu Ihren Benutzern: Geben Sie ihnen Klassen, die die Datenkonsistenz erzwingen, und schützen Sie sie vor Fehlern beim Entwurf Ihrer Daten .

  4. Ist dies ein kleiner Teil einer Anwendung oder nur eine Transformation von Daten? Passen Sie nicht in eines der oben genannten?

    Eine Klasse könnte zu viel sein; Verwenden Sie ein Array, wenn es Ihnen passt und Sie es leichter finden. Wie oben erwähnt, sollten Sie sich nicht mit einer Klasse befassen, wenn Sie nur strukturierte Daten zum Senden als JSON, YAML oder XML oder was auch immer generieren, es sei denn, dies ist erforderlich. Wenn Sie ein kleines Modul in einer größeren Anwendung schreiben und keine anderen Module / Teams mit Ihrem Code kommunizieren müssen, ist möglicherweise ein Array ausreichend.

Berücksichtigen Sie letztendlich die Skalierungsanforderungen Ihres Codes und berücksichtigen Sie, dass ein strukturiertes Array zwar eine schnelle Lösung darstellt, eine Klasse jedoch eine wesentlich stabilere und skalierbarere Lösung darstellt.

json_data()Beachten Sie außerdem Folgendes: Wenn Sie eine Klasse haben und in JSON ausgeben möchten, gibt es keinen Grund, warum Sie keine Methode Ihrer Klasse definieren können, die ein JSON-fähiges Array der Daten in der Klasse zurückgibt. Das habe ich in meinen PHP-Anwendungen gemacht, in denen ich Klassendaten als JSON senden musste. Als Beispiel:

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());

Da Sie die Elemente von nicht ändern, ist es nicht erforderlich my_lineitems, sie per Referenz abzurufen, da Variablen nur einen Bezeichner für das Objekt enthalten, nicht für das Objekt selbst. php.net/manual/en/language.oop5.references.php
Chinoto Vokro

Einverstanden. Ich denke, das war ein Ausschnitt aus einer viel größeren Anwendung, die den Verweis aus einem bestimmten Grund brauchte, oder so ...
Josh

2

Sie können die Json- Struktur mithilfe der JsonSerializable- Schnittstelle implementieren und verschachtelte Arrays / Klassen auf beliebige Weise verwenden. Class ist schneller in get / set-Operationen und einfacher zu debuggen. Bei Array brauchen Sie keine Deklaration.

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

Was bedeutet diese Frage zusätzlich zu der bereits akzeptierten Antwort?
Esoterik

@esoterik Verschachtelung. json_encode(['order'=>$o]);in existsing akzeptierte Antwort ist leer: {"order":{}}. Sicher können Sie verwenden: $o->forJSON()jedes Mal auf jedem Objekt auf jeder Ebene, aber es ist nicht wirklich gutes Design. Weil du die ganze Zeit etwas schreiben musst wie: $items_json = array(); foreach($this->my_lineitems as $item) $items_json[] = $item->forJSON();
El '
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.