MB: Tipps für die Verwendung von Array oder Objekt

moin,

ich hab mir leider die Angewohnheit zugelegt, das ich für die Datenhaltung Instanz Klassen schreibe wo auch mal ein multidimensionales Array herhalten kann. Ein allgemeiner Leitfaden, wann es sinnvoll ist, ein multidimensionales Array zuverwenden und wann ein resourcenfressendes Objekt, ist echt eine Hilfe 😀. Diesbezüglich: Gibt es generelle Ratschläge die nicht Anwendungsfall spezifisch sind?

lgmb

PS: Gib es eine allgemeine Bezeichnung für Instanz Klassen die keine Methode aufweisen und dessen Instanz Properties alle öffentlich sind?

akzeptierte Antworten

  1. Hallo MB,

    lass mich mit einem Zitat aus dem Handbuch beginnen:

    Ein Array in PHP ist tatsächlich eine geordnete Map. Eine Map ist ein Typ, der Werte zu Schlüsseln zuordnet

    Die Map ermöglicht dir die Nutzung als Key-Value Speicher, auch Hashtable oder Dictionary genannt. Numerische Keys haben Sonderstatus und ermöglichen den Gebrauch als Array im engeren Sinne, d.h. eine Datenstruktur aus Werten gleichen Typs, die an fortlaufend nummerierten Positionen gespeichert sind.

    Die geordnet-Eigenschaft ermöglicht dazu Nutzungen als Liste, Stack oder Queue.

    Ein Objekt ist eine Datenstruktur mit einer wohldefinierten und nicht zur Laufzeit erweiterbaren Menge aus Eigenschaften und Methoden. Elemente dieser Menge können von außen zugänglich sein oder nicht. Die Definition entsteht durch die Klasse (das ist eine Definition für PHP). In manchen Sprachen ist der Zugriff auf Objekteigenschaften deutlich fixer als auf Einträge in einer Map, aber nicht in PHP.

    In der Praxis kann es etwas verschwimmen (anonyme Funktionen als Arraywert und magische Methoden), aber das sind die beiden Eckpunkte.

    Du musst dich also fragen, was du da eigentlich hast. Und dann die passende Implementierung nehmen.

    Objekte die einfach nur eine Sammlung aus öffentlichen Eigenschaften sind, nennt man übrigens PO?Os (Plain Old ? Objects), wobei das ? für die Sprache steht. Java: POJO, C++, .net: POCO, PHP: POPO.

    Rolf

    --
    sumpsi - posui - clusi
    1. Moin,

      [...] PO?Os (Plain Old ? Objects), wobei das ? für die Sprache steht. Java: POJO, C++, .net: POCO, PHP: POPO.

      sehr nett. *fg*

      Wobei POPO in der Microcontroller-Entwicklung manchmal auch als Kürzel für einen Reset durch Aus- und Wiedereinschalten (Power-Off Power-On) verwendet wird.

      Ciao,
       Martin

      --
      Ich stamme aus Ironien, einem Land am sarkastischen Ozean.
    2. moin,

      […]. In manchen Sprachen ist der Zugriff auf Objekteigenschaften deutlich fixer als auf Einträge in einer Map, aber nicht in PHP.

      schade, habs aber beführchtet.

      In der Praxis kann es etwas verschwimmen (anonyme Funktionen als Arraywert und magische Methoden), aber das sind die beiden Eckpunkte.

      Daran habe ich nicht gedacht. Danke für den Tipp.

      Du musst dich also fragen, was du da eigentlich hast. Und dann die passende Implementierung nehmen.

      werde wohl - wie üblich - Objekte mit einer Konstruktor Methode und öffentlichen Eigenschaften verwerden.

      Objekte die einfach nur eine Sammlung aus öffentlichen Eigenschaften sind, nennt man übrigens PO?Os (Plain Old ? Objects), wobei das ? für die Sprache steht. Java: POJO, C++, .net: POCO, PHP: POPO.

      Danke für die Erklärung 😀!!!

      Kann man die Objekte auch mit POPO bezeichnen, da sie ja eine Methode - den Konstruktor - aufweisen, der nur dazu dient, die Werte auf die Eingenschaften im Objekt zu setzen.

      lgmb

      1. Hallo MB,

        Kann man die Objekte auch mit POPO bezeichnen, da sie ja eine Methode - den Konstruktor - aufweisen, der nur dazu dient, die Werte auf die Eingenschaften im Objekt zu setzen.

        Nein, sollte man nicht. Ein POPO besteht nur aus Properties.

        Ein readonly-POPO ist was anderes, aber dafür gibt's in PHP kein Sprachmittel. In 2014 wurde ein readonly Schlüsselwort diskutiert, aber verworfen. Besser wären getter und setter für Properties, aber der RFC dafür bekam nicht die nötige 2/3 Mehrheit.

        Um ein readonly Objekt zu bekommen, musst Du die Werte also immer noch private speichern und zum Lesen eine Unterstützung über __get anbieten. Bei __set schmeißt Du einen Fehler. Oder explizt den Boilerplate-Code für Property-Getter programmieren.

        Rolf

        --
        sumpsi - posui - clusi
    3. Tach!

      Du musst dich also fragen, was du da eigentlich hast. Und dann die passende Implementierung nehmen.

      Ergänzend dazu meinen Standpunkt. Ein Array im allgemeinen Sinne ist normalerweise eine Sammlung von gleichartigen Dingen. In anderen Sprachen ist die Länge konstant oder anders gesagt die Anzahl der Elemente. Variable Anzahl von Elementen werden meist als List(e) verwaltet. Dazu kommen noch andere Container, zum Beispiel Map oder Dictionary, bei denen man ihre Elemente nicht über einen Index anspricht, sondern die Name-Value-Paare verwalten.

      PHP hat diese und weitere Anwendungsfälle zusammengefasst und verkauft es als Array. Für deine Frage sind die Fälle herkömmliches Array, Liste und Map/Dictionary relevant.

      Man kann ein Dictionary auch als Sammlung unterschiedlicher Dinge verwenden, wenn die Sprache keine feste Typisierung hat, wie es bei PHP der Fall ist. Damit kann man auch das nachbilden, was bei stark typisierten Sprachen ein Objekt (oder Struct) erfordert, ein Container für die Zusammenfassung von Eigenschaften unterschiedlichen Typs. Üblicherweise beschreibt ein Objekt (oder die Klasse als dessen Bauplan) ein konkretes Ding, das mehrere Eigenschaften hat.

      Was also nun nehmen? Wie gesagt, kannst du PHP-Arrays als assoziative Arrays genauso verwenden wie Objekte. Sinnvoll ist das aber nur begrenzt, vor allem bei kleineren Anwendungen hat das kaum Nachteile. Wenn deine Anwendung aber objektorientiert ist, dann solltest du für deine Datenobjekte auch Objekte verwenden, und Arrays nur als Container, um mehrere gleichartige Dinge abzulegen.

      Dazu kommt, dass eine IDE die Definition der Eingenschaften in Klassen lesen kann und somit weiß, welche Eigenschaftsnamen sie bei der Autovervollständigung oder der statischen Code-Analyse berücksichtigen kann. Keys in assoziativen Array hingegen sind lediglich Strings, auch Magic Strings genannt. Nimmt man den richtigen String, passiert sozusagen Magie, sonst nicht. Maps / Dictionarys / assoziative Arrays eigenen sich also eher als Container, wenn die Namen / Keys zu den Werten nicht bereits zur Entwicklungszeit bekannt sind.

      dedlfix.

      1. moin,

        Was also nun nehmen? Wie gesagt, kannst du PHP-Arrays als assoziative Arrays genauso verwenden wie Objekte. Sinnvoll ist das aber nur begrenzt, vor allem bei kleineren Anwendungen hat das kaum Nachteile. Wenn deine Anwendung aber objektorientiert ist, dann solltest du für deine Datenobjekte auch Objekte verwenden, und Arrays nur als Container, um mehrere gleichartige Dinge abzulegen.

        Vielen Dank, so hatte ich das auch im Kopf. Schon das es mir bestätigt wird 😀. lgmb

    4. Hello,

      lass mich mit einem Zitat aus dem Handbuch beginnen:

      Ein Array in PHP ist tatsächlich eine geordnete Map. Eine Map ist ein Typ, der Werte zu Schlüsseln zuordnet

      Die Map ermöglicht dir die Nutzung als Key-Value Speicher, auch Hashtable oder Dictionary genannt. Numerische Keys haben Sonderstatus und ermöglichen den Gebrauch als Array im engeren Sinne, d.h. eine Datenstruktur aus Werten gleichen Typs, die an fortlaufend nummerierten Positionen gespeichert sind.

      Kurze Zwischenfrage (auf PHP bezogen):

      woher nimmst Du die Festlegung mit "gleichen Typs"? MWn ist das speziell bei PHP auch bei numerisch indizierten Elementen unerheblich, welchen Typs die sind, oder?

      Wenn ich Dich da jetzt falsch verstanden haben sollte, erkläre es bitte nochmal für'n Doofen ;-p

      @MB:

      Bei PHP liegt der Knackepunkt mMn bei den unterschiedlichen Vorgehensweisen für dide Serialisierung von "Arrays" und Objekten, wenn man sie z. B. in der Session zwischenspeichern will. Im Hintergrund sind beides keine geschlossenen Speicherstrukturen mehr, sondern Haufen von Referenzen auf Einzelelemente/Members.

      Glück Auf
      Tom vom Berg

      --
      Es gibt nichts Gutes, außer man tut es!
      Das Leben selbst ist der Sinn.
      1. Hallo Tom,

        PHP ist ungetypt, darum kann ich das Ding, das PHP Array nennt, beliebigen Kram hineinschmeißen. PHP ist aber für seine Striktheit in Bezug auf Informatik-Konzepte genauso bekannt wie Zwerge für ihren Humor.

        Die Idee des abstrakten Konzepts „Array“ ist meiner Auffasung nach, dass die Indexe kompakt sind und die Werte vom gleichen Typ.

        Rolf

        --
        sumpsi - posui - clusi
        1. Hello,

          Die Idee des abstrakten Konzepts „Array“ ist meiner Auffasung nach, dass die Indexe kompakt sind und die Werte vom gleichen Typ.

          Das habe ich in Nicolas' Abstracts noch enger gelernt:
          Der (Index x Typbreite) + Startoffset ergibt die Position des Elementes im Speicher. Daher verbraucht der Index selber auch keinen Platz. Die Position ist berechenbar.

          PHPs "Arrays" stellen sich zum Verständnis besser als verkettete Listen, bzw. Bäume dar. Dass sie im Hintergrund mit Hashtables o. ä. arbeiten, interessiert für das Verständnis der Funktionsweise nicht besonders. Insofern unterscheiden sich in PHP "Arrays" und Objekte im Aufbau ohnehin nicht viel.

          Da der OP das nun aber allgemein unter "Programmiertechnik" gefragt hat, und ich von JS nur tangential Ahnung habe, würde mich noch intetessieren, wie es dort (JS) geregelt ist.

          Glück Auf
          Tom vom Berg

          --
          Es gibt nichts Gutes, außer man tut es!
          Das Leben selbst ist der Sinn.
          1. Tach!

            PHPs "Arrays" stellen sich zum Verständnis besser als verkettete Listen, bzw. Bäume dar. Dass sie im Hintergrund mit Hashtables o. ä. arbeiten, interessiert für das Verständnis der Funktionsweise nicht besonders. Insofern unterscheiden sich in PHP "Arrays" und Objekte im Aufbau ohnehin nicht viel.

            Hmm, ich wüsste grad nicht, wie mir die Vorstellung von verketteten Listen oder Bäumen beim Verstehen von PHPs Array helfen können. Da finde ich eher die Map hilfreicher. Wie die intern aufgebaut ist, ob sie was hashen muss oder nicht, ist mir aber auch egal, solange ich PHP nur verwenden und nicht selbst ändern möchte.

            Da der OP das nun aber allgemein unter "Programmiertechnik" gefragt hat, und ich von JS nur tangential Ahnung habe, würde mich noch intetessieren, wie es dort (JS) geregelt ist.

            Das MDN beschreibt das Array-Objekt so: "The JavaScript Array class is a global object that is used in the construction of arrays; which are high-level, list-like objects." Es ist also ein Objekt, das so tut, als ob es ein Array wäre. Aber es stellt auch Methoden bereit, um mit den Daten des Arrays zu arbeiten.

            dedlfix.

            1. Hello,

              Tach!

              PHPs "Arrays" stellen sich zum Verständnis besser als verkettete Listen, bzw. Bäume dar. Dass sie im Hintergrund mit Hashtables o. ä. arbeiten, interessiert für das Verständnis der Funktionsweise nicht besonders. Insofern unterscheiden sich in PHP "Arrays" und Objekte im Aufbau ohnehin nicht viel.

              Hmm, ich wüsste grad nicht, wie mir die Vorstellung von verketteten Listen oder Bäumen beim Verstehen von PHPs Array helfen können. Da finde ich eher die Map hilfreicher. Wie die intern aufgebaut ist, ob sie was hashen muss oder nicht, ist mir aber auch egal, solange ich PHP nur verwenden und nicht selbst ändern möchte.

              Es geht mir dabei um die Tatsache, dass keine direkten Zugriffe auf die Daten, sondern mehrfach indirekte stattfinden und wie sich Bezeichner bzw. Pseudoindex und die Reihenfolge der Elemente verhalten. Gerade bei mehrdimensionalen "Arrays" hilft die Vorstellung als Baumstruktur mMn, die Funktionsweise der Arrayfunktionen leichter zu verstehen.

              Glück Auf
              Tom vom Berg

              --
              Es gibt nichts Gutes, außer man tut es!
              Das Leben selbst ist der Sinn.
              1. Hallo TS,

                jetzt bist Du aber auf einer anderen Betrachtungsebene: Verwenden von Arrays, insbesondere Arrays of Arrays, in PHP Programmen, unter Benutzung der Array-Funktionsbibliothek.

                Bisher waren wir bei der Implementierung des PHP Typs "Array".

                Rolf

                --
                sumpsi - posui - clusi
      2. Tach!

        Die Map ermöglicht dir die Nutzung als Key-Value Speicher, auch Hashtable oder Dictionary genannt. Numerische Keys haben Sonderstatus und ermöglichen den Gebrauch als Array im engeren Sinne, d.h. eine Datenstruktur aus Werten gleichen Typs, die an fortlaufend nummerierten Positionen gespeichert sind.

        Kurze Zwischenfrage (auf PHP bezogen):

        woher nimmst Du die Festlegung mit "gleichen Typs"? MWn ist das speziell bei PHP auch bei numerisch indizierten Elementen unerheblich, welchen Typs die sind, oder?

        Im Prinzip ja. Mittlerweile hat zwar Type Hinting in PHP um sich gegriffen, aber die Elemente von Arrays kann man nach wie vor nicht per Type Hint festklopfen.

        @MB:

        Bei PHP liegt der Knackepunkt mMn bei den unterschiedlichen Vorgehensweisen für dide Serialisierung von "Arrays" und Objekten, wenn man sie z. B. in der Session zwischenspeichern will.

        Kann ich nicht nachvollziehen. Beides kann man problemlos wiederherstellen. (Spezielle Anforderungen kann man bei Klassen mit __sleep() und __wakeup() implementieren.) Außerdem ist ja nicht in jedem Fall gegeben, dass man serialisieren möchte, so dass ich das nicht als ein allgemeingültiges Kriterium bei der Entscheidung zwischen Array und Klasse sehe.

        dedlfix.

    5. Ein Objekt ist eine Datenstruktur mit einer wohldefinierten und nicht zur Laufzeit erweiterbaren Menge aus Eigenschaften und Methoden.

      Das ist nicht nur falsch sondern stellt sogar die OOP in Frage. Warum sollte die Menge an Eigenschaften zur Laufzeit nicht erweiterbar sein!? Und warum sollte eine Instanz nicht um Methoden erweiterbar sein die zur Laufzeit bereitgestellt werden!?

      Moderne Design'Patterns befassen sich genau mit dieser Frage und insbesondere damit wie man Instanzen zur Laufzeit verändert und der Art und Weise wie man einer Instanz zur Laufzeit Methoden und Eigenschaften hinzufügt.

      MFG

      1. Tach!

        Moderne Design'Patterns befassen sich genau mit dieser Frage und insbesondere damit wie man Instanzen zur Laufzeit verändert und der Art und Weise wie man einer Instanz zur Laufzeit Methoden und Eigenschaften hinzufügt.

        Du beschäftigst dich zwar damit, aber anderenorts versucht man sowas gern zu vermeiden. Diese Dynamik zur Laufzeit ist etwas, das sich schwer kontrollieren lässt, vor allem von Werkzeugen, mit denen man Code-Qualität sicherstellen möchte. Moderne Design Pattern befassen sich eher mit der Entkopplung von Dingen gemäß dem Single Responsibility Principle statt dem Zusammenbau von Dingen, die nicht zusammengehören.

        dedlfix.

  2. Eine Instanz referenziert Eigenschaften, das drückt der Pfeiloperator aus. So kann

      $f->STATS;
    

    nicht nur auf einen String verweisen sondern auch auf ein Array

      $f->STATS['mtime']
    

    während

      $file['STATS']['mtime']
    

    nicht referenziert.

    MFG

    1. moin,

      Eine Instanz referenziert Eigenschaften, […]

      em sorry, was willst du mir damit sagen??? Das geht an meiner Eingangsfrage im Thread völlig vorbei - fals ich dich richtig verstanden habe versteht sich 😉.

      lgmb

      1. Nun, die Verwendung ob Array oder Objekt ergibt sich ja eben daraus, also aus dem Unterschied ob Daten referenziert oder kopiert werden.

        Wahrscheinlich ist das einem PHP Programmierer gar nicht klar, daß beim Aufruf einer Methode mit $ob->methode() eine Übergabe des Objekts in dieselbe stattfindet und ebenda als $this verfügbar ist.

        Und somit nicht eine Kopie der Daten übergeben wird sondern nur eine Referenz, womit die Daten nicht doppelt und dreifach im Hauptspeicher gehalten werden müssen.

        MFG

        1. Tach!

          Nun, die Verwendung ob Array oder Objekt ergibt sich ja eben daraus, also aus dem Unterschied ob Daten referenziert oder kopiert werden.

          Ob die Übergabe einer Variable per Referenz oder Kopie erfolgt, ist kein geeignetes Entscheidungsmerkmal, ob Arrays oder Objekte eingesetzt werden sollten. Bei beiden gibt es Möglichkeiten das jeweils andere als das Default-Verhalten zu erzwingen. Außerdem arbeitet PHP mit Copy-on-Write, so dass es intern Referenzen verwendet, solange die Daten nicht geändert werden. Somit ist Kopie vs. Referenz noch weniger ein geeignetes Unterscheidungsmerkmal.

          Schaut man zudem auf andere Sprachen, wie C# oder C++, dann gibt es dort neben class auch struct. Structs sind sozusagen Klassen, die als Kopie übergeben werden. Bei der Entscheidung, ob eine Klasse, ein Struct, ein Array, eine List, eine Map oder ein Dictionary verwendet werden, spielt das Default-Verhalten bei Zuweisungen keine Rolle. Das kommt lediglich bei der Entscheidung zwischen Class und Struct zum tragen.

          Wahrscheinlich ist das einem PHP Programmierer gar nicht klar,

          Weniger Arroganz wäre angebracht.

          Und somit nicht eine Kopie der Daten übergeben wird sondern nur eine Referenz, womit die Daten nicht doppelt und dreifach im Hauptspeicher gehalten werden müssen.

          Dafür gibt es das interne Copy-on-Write-Prinzip bei PHP.

          dedlfix.

  3. Man kann's auch so sehen, Objekte haben Methoden, Arrays nicht. Oder anders ausgedrückt, wenn Deine Daten Methoden brauchen, dann halte die Daten als Objekt. Das ist einer der Grundgedanken die im MVC stecken.

    MFG

    1. moin,

      Man kann's auch so sehen, […]

      siehe hier

      lgmb

  4. Hallo MB,

    resourcenfressendes Objekt

    dazu ein Nachtrag. PHP Arrays sind, wie zitiert, geordnete Maps. Das ist auch keine triviale Struktur. Aber man kann ja messen.

    Das folgende Beispiel verwendet wahlweise ein Objekt oder ein Array, um ein paar Werte zu speichern. Ich rechne ein bisschen rum damit der PHP Compiler nichts wegoptimiert. Die erzeugten Objekte bzw. Arrays werden in einem Array gesammelt, um den Speicher messen zu können.

    (Edit 12:38 Uhr: Elemente in $buf[$i] speichern statt in $f)

    class Foo {
        public $bar, $baz, $fup, $hup, $bup;
        function __construct($t) {
            $this->bar = $t+1;
            $this->baz = $t+2;
            $this->fup = $t+3;
            $this->hup = $t+4;
            $this->bup = $t+5;
        }
    }
    
    $start = microtime(TRUE);
    $m0 = memory_get_usage();
    
    $buf = [];
    
    for ($i=0; $i<10000; $i++)
    {
        $buf[$i] = new Foo($i);
    //  $buf[$i] = [ "bar" => $i+1, "baz" => $i+2, "fup" => $i+3, "hup" => $i+4, "bup" => $i+5 ];
    }
    
    $memory = (memory_get_usage()-$m0)/1024;
    $time = (microtime(TRUE) - $start)*1000000;
    
    echo "Laufzeit: $time µs, Speicher: $memory KB";
    

    Die leere Schleife braucht 100µs, und die Laufzeit mit Inhalt variiert auf PHP Sandbox von 1200 bis 2000 Mikrosekunden, egal welche Zeile ich in die Schleife einkommentiere. Es sind 10000 Durchläufe, d.h. die Erzeugung eines Objekts oder eines Arrays liegt im Bereich von 160±40 Nanosekunden.

    Das ist für alle Anwendungszwecke, mit denen wir hier zu tun haben, komplett zu vernachlässigen. Du musst Dich also bei deinen Überlegungen für Objekt oder Array nicht von Performancefragen leiten lassen.

    Anders ist es beim Speicher. Die Array-Version erhöht den von memory_get_usage gelieferten Wert um 4187 KB, also gut 4 Megabytes. Die Objektversion belegt dagegen 2198 KB, spart also ca die Hälfte.

    Bei 10 statt 5 Properties wächst der Speicherbedarf bei Arrays auf 7312 KB und bei Objekten auf 2823 KB, d.h. der Preis pro Property ist bei Arrays höher als bei Objekten. Die Namenslänge der Properties spielt dagegen keine Rolle, weil PHP bei einem mehrfach verwendeten String nur Referenzen speichert.

    Wichtig ist aber die PHP Version. Es kann zwar auch an den Sandbox-Servern liegen, aber PHP 7 ist deutlich schneller und auch effizienter bei Objekten. Die Durchlaufzeit der Testschleife stieg bei ältere PHP Versionen (vor 7) auf über 4000µs und war bei Objekten noch deutlich langsamer (6000µs und mehr). Ab PHP 7 nähern sich die Zeiten an und werden absolut betrachtet deutlich kleiner, mit einem leichten Vorteil für Arrays. Insbesondere halbiert sich bei PHP 7 der gemeldete Speicherbedarf - woran auch immer das liegt.

    D.h. wenn Du aus irgendwelchen Gründen an PHP 5 festklebst, können Arrays in Hochlastsituationen Zeitvorteile bieten, erkauft mit deutlich höherem Speicherbedarf. Allerdings wäre in Hochlastsituationen eher eine andere Sprache angebracht, und sei es auch nur Hack und die HHVM statt PHP mit der ZEND Engine.

    Rolf

    --
    sumpsi - posui - clusi
    1. Hello,

      wichtig ist auch, ob 32- oder 64-Bit-Version und in welchen Häppchen das OS den Speicher zuordnen mag.

      Bei Arrays mit numerischen Zweigen kommt noch hinzu, wie herum man sie aufbaut.

      Wenn man die Nummer tatsächlich als Index benutzt, spart das viel Speicher und macht die Bearbeitung (meistens) schneller. Ich habe aus diesem Grund mal eine Betrachtung "Arrays mal anders herum" angestellt. Der Artikel dazu wurde aber scheinbar aus dem Wiki entfernt.

      Man hätte ihn besser in meinen Userspace zurückschieben können!

      Glück Auf
      Tom vom Berg

      --
      Es gibt nichts Gutes, außer man tut es!
      Das Leben selbst ist der Sinn.
      1. Man hätte ihn besser in meinen Userspace zurückschieben können!

        Das Internet Archive hat noch ein Backup deines Artikels gepseichert.

        Unabhängig davon befürworte ich die Entscheidung den Artikel nicht weiter im Wiki zu veröffentlichen.

    2. Tach!

      Anders ist es beim Speicher. Die Array-Version erhöht den von memory_get_usage gelieferten Wert um 4187 KB, also gut 4 Megabytes. Die Objektversion belegt dagegen 2198 KB, spart also ca die Hälfte.

      Kann ich mit der PHP Sandbox nicht nachvollziehen. Ich wüsste auch nicht, warum da megabyteweise Speicher benötigt würde.

      Speicher: 1.2265625 KB bei PHP 5.x (mit x größer 4)
      Speicher: 0.3671875 KB ab PHP 7.0

      Im Vergleich dazu die Objekt-Version:

      Speicher: 0.828125 KB bei PHP 5.x
      Speicher: 0.125 KB ab PHP 7.0

      Da ist auch kein Unterschied zwischen einem und 10000 Schleifendurchläufen.

      Wichtig ist aber die PHP Version. Es kann zwar auch an den Sandbox-Servern liegen, aber PHP 7 ist deutlich schneller und auch effizienter bei Objekten.

      Auch innerhalb der Major-Version gibt es Unterschiede. So ist zum Beispiel bei 7.3 der Garbage Collector optimiert worden.

      dedlfix.

      1. Hallo dedlfix,

        hast Du den Code von mir genommen, den ich ursprünglich gepostet hatte? Der hatte für die Speichermessung den Bug, dass er das Element vom letzten Durchlauf immer überschrieben hat.

        Das hatte ich in der Sandbox geändert, diese Änderung aber nicht gepostet. Das habe ich nun nachgetragen - damit ergeben sich die Speichermengen.

        Rolf

        --
        sumpsi - posui - clusi
        1. Tach!

          hast Du den Code von mir genommen, den ich ursprünglich gepostet hatte?

          Ja. Mit dem geänderten Code sind die Zahlen nachvollziehbar.

          Aber streich mal die Zeile

          public $bar, $baz, $fup, $hup, $bup;

          aus deiner Klassendefinition, dann ist der Speicherverbrauch vom Objekt höher, aber in derselben Region.

          Ich erkläre mir das so: Bei Klassen mit vordefinierten Eigenschaftsnamen kann der Compiler den Namen wegoptimieren. Alle Instanzen folgen ja demselben Bauplan. Die Arrays könnten jedesmal andere Key-Namen haben, und benötigen die Namensinformation. Arrays haben keinen Bauplan, aus dem das hervorgehen kann. Objekte mit zur Laufzeit hinzugefügten Eigenschaften müssen sich ebenfalls die Eigenschaftsnamen individuell in jeder Instanz merken. Die könnten ja wie beim Array die Keys jeweils andere sein.

          dedlfix.

  5. PS: Gib es eine allgemeine Bezeichnung für Instanz Klassen die keine Methode aufweisen und dessen Instanz Properties alle öffentlich sind?

    Jede Instanz hat wenigstens eine Methode __destruct() und weitere Methoden die Du unter Magic Methods im Handbuch finden kann.

    Die allgemeine Bezeichnung dafür lautet Vererbung. D.H., daß jede Instanz diese magischen Methoden erbt.

    Properties von außen zugänglich zu machen ist eine Frage der Zweckmäßigkeit.

    MFG

    1. Tach!

      PS: Gib es eine allgemeine Bezeichnung für Instanz Klassen die keine Methode aufweisen und dessen Instanz Properties alle öffentlich sind?

      Jede Instanz hat wenigstens eine Methode __destruct() und weitere Methoden die Du unter Magic Methods im Handbuch finden kann.

      Keine der Magic Methods ist vorhanden, wenn man sie nicht erstellt.

      Die allgemeine Bezeichnung dafür lautet Vererbung. D.H., daß jede Instanz diese magischen Methoden erbt.

      Vererbung ist nicht im Spiel, wenn man keine verwendet. Da wird auch nichts implizit von irgendeiner (internen) Superklasse geerbt, wie das beispielsweise bei C# mit der Klasse Object der Fall wäre.

      Properties von außen zugänglich zu machen ist eine Frage der Zweckmäßigkeit.

      Auch das hat, wie die beiden obigen Aussagen nichts mit der Frage im OP oder der zitierten zu tun.

      dedlfix.

      1. Hallo dedlfix,

        Vererbung ist nicht im Spiel, wenn man keine verwendet. Da wird auch nichts implizit von irgendeiner (internen) Superklasse geerbt, wie das beispielsweise bei C# mit der Klasse Object der Fall wäre.

        Es wäre aber eine plausible Implementierung der Magic Methods. Hast Du eine Quelle, aus der hervorgeht, dass es sich dabei nicht um virtuelle Methoden einer internen Object Superklasse handelt?

        Es ist jedenfalls so, dass man eine __get Methode nicht explizit aufrufen kann. Weder von außerhalb noch aus einer Methode heraus. Und parent:: ohne Vererbung wird auch nicht akzeptiert. Von daher sieht es so aus, als ob Du recht hast.

        Rolf

        --
        sumpsi - posui - clusi
        1. Tach!

          Vererbung ist nicht im Spiel, wenn man keine verwendet. Da wird auch nichts implizit von irgendeiner (internen) Superklasse geerbt, wie das beispielsweise bei C# mit der Klasse Object der Fall wäre.

          Es wäre aber eine plausible Implementierung der Magic Methods. Hast Du eine Quelle, aus der hervorgeht, dass es sich dabei nicht um virtuelle Methoden einer internen Object Superklasse handelt?

          Nein, ich nehme an, dass sie anhand des Namens gefunden werden. Müsste man im Code nachschauen, wenn es wirklich interessiert. Ich sehe keinen Sinn darin, das über Vererbung und einer internen Superklasse zu lösen. Das werden ganz normale Methodenaufrufe sein, nur dass sie einen festgelegten Namen haben. Methoden mit anderen Namen müssen auch direkt aufgerufen werden können, ohne dass eine Superklasse sie vordefiniert.

          Es ist jedenfalls so, dass man eine __get Methode nicht explizit aufrufen kann. Weder von außerhalb noch aus einer Methode heraus.

          Doch, das geht problemlos. Das sind an sich stinknormale Funktionen, selbst __construct().

          <?php
          
          class foobar {
              function __construct($param) {
                  echo $param;
              }
              
              function __get($name) {
                  return $name;
              }
              
              function foo() {
                  return $this->__get('bar');
              }
          }
          
          $x = new foobar('foo');
          $x->__construct('bar');
          
          echo $x->__get('foo');
          echo $x->foo();
          

          dedlfix.

          1. Hallo dedlfix,

            da haben wir uns missverstanden. Ich wollte sie aufrufen, OHNE sie zu definieren. Weil - wenn das gegangen wäre, dann hätte es eine geheime Default-Implementierung gegeben (die z.B. von einer Superklasse geerbt ist).

            Aber das ging nicht. Also gibt's auch keine erkennbare Default-Implementierung, und es ist wohl wie du sagst: Wenn PHP an die Stelle kommt, wo es Magie braucht, versucht es einen dynamischen Methodenaufruf auf die entsprechende Methode.

            Rolf

            --
            sumpsi - posui - clusi
    2. Properties von außen zugänglich zu machen ist eine Frage der Zweckmäßigkeit.

      Und eine Frage der Dokumentation! D.h., daß ein Entwickler seine API's sauber dokumentiert.

      MFG

  6. Ein allgemeiner Leitfaden, wann es sinnvoll ist, ein multidimensionales Array zuverwenden und wann ein resourcenfressendes Objekt, ist echt eine Hilfe

    Da PHP-Variablen (Arrays, Hashes/„named arrays“, wie schon beschrieben) einerseits „alles außer typsicher“ sind, anderseits der Zugriff auf einen Array schneller, ist eine Klasse/Objekt das Mittel der Wahl wenn ich

    • via „setter“ Typsicherheit und/oder Plausibilität der Items sicher stellen will. (Dann sind die Items aber mit Sicherheit nicht „public“).
    • via getter Ausgaben unterschiedlich steuern will (da gabs erst neulich eine Diskussion, wo die Daten als Array oder JSON ausgegeben wurden, allerdings mit kruden Namen der Methoden.)

    Ein Test der Zugriffsgeschwindigkeiten:

    Ich habe mal versucht, einen fairen Test zu schreiben. Erzeugt wird ein Array, ein Hash („named array“) sowie jeweils ein simples Objekt, welches den Array bzw. Hash enthält. Aus dem Array/Objekt mit Array und aus dem Hash/Objekt mit Hash wird dann jeweils mit „gettern“ gelesen.

    <?php
    
    class oArr {
    	var $arr = false;
    	function __construct ( $arr ) {
    		$this->setArr( $arr );
    	}
    	function setArr( $arr ) {
    		$this->arr = $arr;
    	}
    	function getArr ( ) {
    		return $this->arr;
    	}
    	function getItem ( $i ) {
    		if ( isset( $this->arr[$i] ) ) {
    			return $this->arr[$i];
    		} else {
    			return false;
    		}
    	}	
    }
    
    class oHash {
    	var $hash = false;
    	function __construct ( $hash ) {
    		$this->sethash( $hash );
    	}
    	function setHash( $hash ) {
    		$this->hash =  $hash;
    	}
    	function getHash ( ) {
    		return $this->hash;
    	}
    	function getItem ( $s ) {
    		if ( isset( $this->hash[$s] ) ) {
    			return $this->hash[$s];
    		} else {
    			return false;
    		}
    	}		
    }
    
    $s     ='ABCDEFGHIJKLMNOPQRSTYUVWXYZ';
    $items = 10000;
    $max   = strlen( $s ) - 1;
    
    
    $arr  = [];
    $hash = [];
    for ( $i=0; $i < $items; $i++ ) {
    	$string = '';
    	for ( $k=0; $k < rand(4, 8); $k++ ) {
    		$string .= $s[ rand(0, $max ) ];
    	}
    	$arr[]         = $string;
    	$hash[$string] = $i;
    }
    
    $Arr  = new oArr ( $arr );
    $Hash = new oHash ( $hash ) ;
    
    $start = microtime( true );
    foreach ( $arr as $s ) {
        $dummy = $s;
    }
    $time = microtime( true ) - $start;
    echo "foreach über gesamten Array ( $items Items ) : $time Sekunden " . PHP_EOL;
    
    $time = microtime( true ) - $start;
    for ( $i = 0; $i < $items; $i++ ) {
       	$dummy = $arr[$i];
    }
    $time = microtime( true ) - $start;
    echo "for i über gesamten Array   ( $items Items ) : $time Sekunden " . PHP_EOL;
    
    $time = microtime( true ) - $start;
    for ( $i = 0; $i < $items; $i++ ) {
       	$dummy = $Arr->getItem( $i );
    }
    $time = microtime( true ) - $start;
    echo "for i über Objekt           ( $items Items ) : $time Sekunden " . PHP_EOL;
    echo "------------------------------------------------------------------------------------" . PHP_EOL;
    
    $time = microtime( true ) - $start;
    foreach ( $arr as $s ) {
       	$dummy = $hash[$s];
    }
    $time = microtime( true ) - $start;
    echo "Alle Items des Hashes       ( $items Items ) : $time Sekunden " . PHP_EOL;
    
    $time = microtime( true ) - $start;
    foreach ( $arr as $s ) {
       	$dummy = $Hash->getItem( $s );
    }
    $time = microtime( true ) - $start;
    echo "Alle Items des Hash-Objects ( $items Items ) : $time Sekunden " . PHP_EOL;
    

    Ergebnis:

    foreach über gesamten Array ( 10000 Items ) : 0.00083422660827637 Sekunden 
    for i über gesamten Array   ( 10000 Items ) : 0.0027182102203369 Sekunden 
    for i über Objekt           ( 10000 Items ) : 0.01047420501709 Sekunden 
    ------------------------------------------------------------------------------------
    Alle Items des Hashes       ( 10000 Items ) : 0.01156210899353 Sekunden 
    Alle Items des Hash-Objects ( 10000 Items ) : 0.018543004989624 Sekunden
    

    Fazit:

    • Zugriff auf Array ist signifikant (Faktor 3.9) schneller als Objekt.
    • Allerdings ist der Unterschied „deutlich weniger signifikant“ (Faktor 1.6) bei einem Zugriff auf einen Hash(„named array“) im Verhältnis zu einen Objekt.
    1. Hallo Raketentester,

      was ist daran jetzt fair? Was Du gebenchmarkt hast, ist „PHP-Array“ vs „Objekt-Wrapper um ein PHP-Array“. Wenig verwunderlich, dass der Wrapper langsamer ist.

      Für Datenstrukturen mit variablen Keys sind native PHP Arrays ideal, da muss man nichts wrappen - es sei denn, man muss Zusatzfunktionalität bereitstellen. Z.B. Type Hints. Oder Plausibilitätsprüfungen.

      Die eigentliche Frage ist aber

      ich hab mir leider die Angewohnheit zugelegt, das ich für die Datenhaltung Instanz Klassen schreibe wo auch mal ein multidimensionales Array herhalten kann.

      gewesen - mit anderen Worten: ob man POPOs als assoziatives Array (aka Hash) oder als Objekt implementiert.

      Rolf

      --
      sumpsi - posui - clusi
      1. Hallo Raketentester,

        was ist daran jetzt fair?

        Ich habe geschrieben: „Ich habe mal versucht, einen fairen Test zu schreiben.“ . Nicht, dass dieser unter allen Umständen, Annahmen oder Betrachtungswinkeln fair ist.

        Was Du gebenchmarkt hast, ist „PHP-Array“ vs „Objekt-Wrapper um ein PHP-Array“.

        Na und? Was Du getestet hast, sind auch nur PHP-Variablen vs. in ein Object gewrappte PHP-Variablen.

        Mich hat halt das „multidimensional“ aus:

        Klassen schreibe wo auch mal ein multidimensionales Array herhalten kann.

        interessiert. Und ja, Ich habe - anders als Du - den Aspekt der Dimensionen (wenn auch, je nach Lesart nur eine oder gar zwei) berücksichtigt.

        Ich neige nicht dazu, ... ach lassen wir den /S.+(ss|ß)/i.

        1. Mich hat halt das „multidimensional“ aus:

          Einer Referenz ist es egal wieviele Dimensions ein Array hat, ein Array hat man sowieso

            $this->MULTIBUMS[foo][bar][baz][bimbo];
                   ^ ab hier ist es ein Array
            ^ ab hier ist es eine Referenz
          

          und natürlich können Datenstrukturen sehr komplex und auch umfangreich sein. Aber ob bspw. eine DBabfrage Objekte oder Arrays liefert hängt davon ab was man damit machen will.

          So will eine TemplateEngine keine Objekte sondern Arrays. Will man jedoch mit den gefetchten Daten eigene Methoden aufrufen geht das nur wenn man sie als Objekte da rausholt. Wo man den Namen der Klasse gleich mit übergibt.

          MFG