Wann sollte ich stdClass verwenden und wann sollte ich ein Array in PHOP-Code verwenden?

68

Inmitten einer Phase großer Umgestaltungen bei der Arbeit möchte ich stdClass ***** einführen, um Daten von Funktionen zurückzugeben, und ich versuche, nicht-subjektive Argumente zu finden, um meine Entscheidung zu unterstützen.

Gibt es Situationen, in denen es am besten ist, eine anstelle der anderen zu verwenden?

Welche Vorteile hätte ich, wenn ich stdClass anstelle von Arrays verwenden würde?


Einige würden sagen, dass Funktionen so klein und spezifisch sein müssen, um einen einzelnen Wert zurückgeben zu können. Meine Entscheidung, stdClass zu verwenden, ist zeitlich begrenzt, da ich hoffe, langfristig die richtigen Wertobjekte für jeden Prozess zu finden.

JonG
quelle
siehe: stackoverflow.com/questions/2056931/… Es beantwortet meine Frage nicht. Er sagt, dass eine "echte" Klasse der beste Ansatz wäre, dem wir (glaube ich) alle zustimmen. Ich würde immer noch gerne wissen, "wann" die Verwendung von stdClass Rückgabewerten besser ist als Arrays.
JonG
Vielleicht möchten Sie Ihr Konzept von Wertobjekten klarstellen. In DDD ist ein Wertobjekt unveränderlich und der Zweck unterscheidet sich erheblich
Gordon
@ Gordon Was ich meinte war, eine "VO-ähnliche" Rückgaberichtlinie von Funktionen. Eine VO als (vorzugsweise) kleines Objekt zu haben, bei dem nur seine Attribute wichtig sind, nicht seine Identität. Haben Sie über Ihre Links versucht herauszufinden, ob für mich (meine Frage) die Diskussion über "VO sollte unveränderlich sein Vs VO kann veränderlich sein" wichtig war? Übrigens sind heutzutage VOs TO (Transfer Objects) für die Sonne. java.sun.com/blueprints/corej2eepatterns/Patterns/…
JonG
Ich bin mir noch nicht sicher, ob Sie einfach das Problem lösen möchten, dass PHP nicht mehrere Rückgabewerte oder etwas anderes unterstützt. Und ja, ist Veränderlichkeit wichtig? Vielleicht suchen Sie nach Tupeln (wie in Python)?
Gordon
@ Gordon Vielen Dank für Ihr Interesse. Wie Sie gerade gesagt haben, konzentriert sich meine Frage wohl hauptsächlich darauf, einen 'guten' Weg (in OOP) zu finden, um mehrere Werte als Rückgabe eines Funktionsaufrufs zu übergeben. Denkst du, ich sollte meine Frage bearbeiten oder diese Kommentare werden den Job machen?
JonG

Antworten:

62

Der übliche Ansatz ist

  • Verwenden Sie Objekte, wenn Sie eine definierte Datenstruktur mit festen Verzweigungen zurückgeben:

     $person
       -> name = "John"
       -> surname = "Miller"
       -> address = "123 Fake St"
    
  • Verwenden Sie Arrays, wenn Sie eine Liste zurückgeben:

      "John Miller"
      "Peter Miller"
      "Josh Swanson"
      "Harry Miller"
    
  • Verwenden Sie ein Array von Objekten, wenn Sie eine Liste strukturierter Informationen zurückgeben:

      $person[0]
        -> name = "John"
        -> surname = "Miller"
        -> address = "123 Fake St"
    
      $person[1]
        -> name = "Peter"
        -> surname = "Miller"
        -> address = "345 High St"
    

Objekte sind nicht für Datenlisten geeignet, da Sie immer einen Schlüssel benötigen, um sie zu adressieren. Arrays können beide Funktionen erfüllen - sie enthalten beliebige Listen und eine Datenstruktur.

Daher können Sie für das erste und dritte Beispiel assoziative Arrays über Objekten verwenden, wenn Sie möchten. Ich würde sagen, das ist wirklich nur eine Frage des Stils und der Vorlieben.

@Deceze macht eine Reihe guter Punkte, wann ein Objekt verwendet werden soll (Validierung, Typprüfung und zukünftige Methoden).

Pekka
quelle
Ich mag / stimme den Argumenten Nr. 1 und 2 sehr zu.
JonG
1
Ich bat um "nicht-subjektive" Argumente. Leider wurde keiner gegeben. Ich bleibe bei Ihrer Antwort (nach den Stimmen anderer), da sie zeigt, was ich von nun an weiter verfolgen werde: Arrays sind für Listen; stdClass für "mehrwertig" / Eigenschaften.
JonG
12
Ich bin damit überhaupt nicht einverstanden. Wenn Sie nur Daten haben, auch strukturierte Daten, sollten Sie Arrays verwenden. Ein Objekt ist ein Datenpaket und das damit verbundene Verhalten. Die Verwendung von stdClass als Array ist einfach ein Missbrauch von stdClass.
GordonM
4
Stimmen Sie GordonM zu, die Illusion eines richtigen Objekts durch die Verwendung von stdClass verursacht mehr Schaden als Nutzen. In fast allen Fällen, in denen ich sehe, dass stdClass verwendet wird, werden immer dynamische Attribute missbraucht - es ist sehr verwirrend, welche Struktur die Klasse hat, und selbst wenn diese Struktur respektiert wird, da bei fast jeder Verwendung Attribute "on the fly" ausgefüllt werden. Wenn Sie möglicherweise Attribute verpassen oder sich nicht die Mühe machen, eine tatsächliche Klasse zu erstellen, können Sie auch ein Array verwenden.
srcspider
Keine objektive Antwort.
William Entriken
42

Die Verwendung stdClassder gleichen Funktion wie ein Array ist meiner Meinung nach nicht sehr nützlich, sondern erhöht lediglich den Overhead eines Objekts ohne wirklichen Nutzen. Sie verpassen auch viele nützliche Array-Funktionen (z array_intersect. B. ). Sie sollten mindestens eine eigene Klasse erstellen, um die Typprüfung zu aktivieren, oder dem Objekt Methoden hinzufügen, damit sich die Verwendung eines Objekts lohnt.

täuschen
quelle
1
Ich mag / stimme besonders zu, was Sie über das Hinzufügen von Methoden zum Objekt sagen, damit es sich lohnt, es zu verwenden.
JonG
18

Ich glaube nicht, dass die Verwendung einer stdClass gegenüber einem Array einen vernünftigen Vorteil hat, solange Sie nur die Absicht haben , mehrere beliebige Datentypen aus einem Funktionsaufruf zurückzugeben .

Da Sie technisch gesehen nicht mehrere Werte nativ zurückgeben können, müssen Sie einen Container verwenden, der alle anderen in PHP verfügbaren Datentypen enthalten kann. Das wäre entweder ein Objekt oder ein Array.

function fn1() { return array(1,2); }
function fn2() { return array('one' => 1, 'two' => 2); }
function fn3() { return (object) array(1,2); }
function fn4() { return (object) array('one' => 1, 'two' => 2); }

All das würde funktionieren. Das Array ist ein winziger vernachlässigbarer Bruchteil schneller und weniger zu tippen. Es hat auch einen klar definierten Zweck im Gegensatz zur generischen stdClass (die ein bisschen wunschgemäß ist, nicht wahr?). Beide haben nur eine implizite Schnittstelle, daher müssen Sie sich die Dokumente oder den Funktionskörper ansehen, um zu wissen, was sie enthalten.

Wenn Sie Objekte um jeden Preis verwenden möchten , können Sie ArrayObject oder SplFixedArray verwenden . Wenn Sie sich jedoch deren APIs ansehen, würden Sie sagen, dass Sie deren Funktionalität für die einfache Aufgabe benötigen, zufällige Mehrfachwerte zurückzugeben? Das glaube ich nicht. Versteh mich aber nicht falsch: Wenn du stdClass verwenden willst, dann benutze es. Es ist nicht so, als würde es irgendetwas kaputt machen. Aber Sie würden auch nichts gewinnen. Um zumindest einige Vorteile hinzuzufügen, können Sie hierfür eine separate Klasse mit dem Namen ReturnValues ​​erstellen.

Könnte eine einfache Tagging-Klasse sein

class ReturnValues {}

oder etwas funktionaler

class ReturnValues implements Countable
{
    protected $values;
    public function __construct() { $this->values = func_get_args(); }
    public function __get($key) return $this->values[$key]; }
    public function count() { return count($this->values); }
}

Zugegeben, es macht nicht viel und das Herausholen der Werte erfolgt immer noch über eine implizite Schnittstelle, aber zumindest hat die Klasse jetzt eine klarere Verantwortung. Sie können diese Klasse erweitern, um ReturnValue-Objekte für bestimmte Vorgänge zu erstellen und diesen eine explizite Schnittstelle zu geben:

class FooReturnValues extends ReturnValues
{
    public function getFoo() { return $this->values['foo']; }
    public function getBar() { return $this->values['foo']; }
}

Jetzt muss sich der Entwickler nur noch die API ansehen, um zu wissen, welche mehreren Werte foo () zurückgeben werden. Das Schreiben konkreter ReturnValue-Klassen für jede Operation, die möglicherweise mehrere Werte zurückgibt, kann natürlich schnell mühsam werden. Und ich persönlich finde das für den ursprünglichen Zweck überarbeitet.

Wie auch immer, hoffe das macht Sinn.

Gordon
quelle
1
Interessant ist Ihr "ReturnValues" -Vorschlag.
JonG
@ JonG Danke. Ich denke, meine zwei Hauptpunkte dafür sind: das zurückgegebene Objekt semantisch klarer zu machen und die Schnittstelle dazu explizit zu machen. Wenn nichts davon wichtig ist, dann ist es wirklich sinnlos, diesen Weg imo zu gehen.
Gordon
Ich mag diese Idee einer Klasse, die generisch ist, aber innerhalb einer bestimmten Domäne / eines bestimmten Zwecks generisch. Es hat das Potenzial, tatsächlich Leistung hinzuzufügen, während stdClasses kaum mehr als eine alternative Darstellung eines assoziativen Arrays ist.
IMSoP
Ich denke, die etwas besser lesbare Syntax ist der Hauptvorteil für die meisten Entwickler. Die Verwendung $options = ['a'=>'str', 'b'=>'str'];ist jedoch fast genauso elegant und ermöglicht die vielen nativen / leistungsstarken Funktionen, die für Arrays erstellt wurden. Ich bleibe also bei Arrays, es sei denn, ich muss einer JSON-Struktur entsprechen.
Justin
4

Nun, es gibt 3 Unterschiede:

  • Sie haben eine Identität. Aus diesem Grund wird standardmäßig Array-Argumente nach Wert und Objekte nach Freigabe aufgerufen .
  • Es gibt einen semantischen Unterschied. Wenn Sie ein Objekt verwenden, versteht jeder, der den Code liest, dass der Wert für das Modell eine Art Berechtigung darstellt, während ein Array als Sammlung oder Karte fungieren soll
  • Und nicht zuletzt wird das Refactoring erheblich einfacher. Wenn Sie eine konkrete Klasse anstelle von stdClass verwenden möchten, müssen Sie lediglich eine andere Klasse instanziieren. Hier können Sie auch Methoden hinzufügen.

greetz
back2dos

back2dos
quelle
2

Das einzige ZIEL Vertrauensvotum, das ich finden kann, ist:

json_decode Verwendet standardmäßig stdClass, daher sollten wir Sterblichen im Userland stdClass für ähnliche Situationen verwenden.

William Entriken
quelle
4
Sie können nur verwenden, json_decode($json, true);wenn Sie Arrays anstelle von Objekten erhalten möchten
Peter
1
Wir Sterblichen im Userland überschreiben nicht nur Standardparameterwerte.
Tishma
1

Ich finde stdClass-Objekte über Arrays nützlich, wenn ich meinen Code sauber und etwas satzartig lesbar halten muss. Nehmen wir zum Beispiel eine Funktion, getProperties()die eine Reihe von Eigenschaften zurückgibt, beispielsweise Daten über eine Person (Name, Alter, Geschlecht). Wenn Sie getProperties()ein assoziatives Array zurückgeben würden, wenn Sie eine der zurückgegebenen Eigenschaften verwenden möchten, würden Sie zwei Anweisungen schreiben:

$data = getProperties();
echo $data['name'];

Wenn getProperties()Sie andererseits eine stdClass zurückgeben, können Sie dies in nur einer Anweisung schreiben:

echo getProperties()->name;
Cojocariu Adrian
quelle
4
Beachten Sie, dass dies nicht mehr gilt, wenn Sie PHP 5.4 oder höher verwenden, da es sich nur um einen Mangel des PHP-Parsers handelt. Sie können jetzt echo getProperties()['name']; 3v4l.org/t6i0r
IMSoP
@IMSoP können Sie, außer dass viele Systeme noch PHP 5.3 verwenden, was einen Fehler auslöst, der einige Entwickler verblüfft :).
musicliftsme
2
@laketuna Ja, daher das "Wenn" in meinem Kommentar :) Beachten Sie auch, dass 5.3 jetzt offiziell nicht unterstützt wird, so dass Leute ihre Hosts / Administratoren
belästigen
1

In Tests von Array gegen Standardklasse ist die Art und Weise, wie PHP mit dynamischen Eigenschaften umgeht, langsamer als bei assoziativen Arrays. Ich sage dies nicht, um die Mikrooptimierung zu argumentieren, sondern wenn Sie dies tun, ist es besser, eine Datenklasse ohne Methoden zu definieren und öffentliche Eigenschaften festzulegen. Besonders wenn Sie PHP 5.4+ verwenden. Unter der Haube werden definierte Eigenschaften direkt auf ein AC-Array ohne Hashtabelle abgebildet, während dynamische Eigenschaften eine Hash-Tabelle verwenden müssen.

Dies hat den zusätzlichen Vorteil, dass es später zu einer vollständigen Klasse wird, ohne dass die Benutzeroberfläche grundlegend überarbeitet werden muss.

bgrohs
quelle
Die Leistungsmerkmale von PHP ändern sich mit jeder Version.
William Entriken