#1 27. Mai 2014 Zuletzt bearbeitet: 27. Mai 2014 Ich habe aus div. Gründen mal einen kleinen Benchmark erstellt um zu ermitteln wie groß der Unterschied zwischen Arrays und Objekten bei lesenden und schreibenden Zugriffen ist. Hierfür habe ich ein ein "kleines" Script erstellt: Pastebin.com Legende: array -> normaler array object -> eine Instanz der Klasse stdclass object (fix) -> eine Instanz der Klasse stdclass Der Zugriff auf die Attribute ist hardcoded. array-ref -> array wurde als Referenz an eine Funktion übergeben array-arg -> array wurde als Wert (Value) an eine Funktion übergeben (copy-on-write wird provoziert) wrapper 1 -> eine Instanz einer Klasse mit "magic" Methoden, welches intern einen array verwendet wrapper 2 -> eine Instanz einer Klasse mit "magic" Methoden, welches nach und nach Attribute die gelesen/schrieben werden setzt wrapper 3 -> eine Instanz einer Klasse die alle Attribute die gelesen/schrieben werden bereits vordefiniert hat wrapper 3 (fix) -> eine Instanz einer Klasse die alle Attribute die gelesen/schrieben werden bereits vordefiniert hat. Der Zugriff auf die Attribute ist hardcoded. wrapper 4 -> eine Instanz einer Klasse die alle Attribute die gelesen/schrieben werden bereits vordefiniert hat. Der Zugriff auf die Attribute erfolgt über getter und setter Methoden. Code der drei Wrapper-Klassen: Spoiler PHP: class Wrapper1 implements IteratorAggregate { private $mem = []; function __get ( $key ) { return $this -> mem [ $key ]; } function __set ( $key , $val ) { $this -> mem [ $key ] = $val ; } function __isset ( $key ) { return isset ( $this -> mem [ $key ]); } public function getIterator () { return new ArrayIterator ( $this -> mem ); }} class Wrapper2 { function __get ( $key ) { return null ; } function __set ( $key , $val ) { $this -> $key = $val ; } function __isset ( $key ) { return false ; }} class Wrapper3 { public $a = 0 , $b = 0 , $c = 0 , $d = 0 , $e = 0 , $f = 0 , $g = 0 ; public $h = 0 , $i = 0 , $j = 0 , $k = 0 , $l = 0 , $m = 0 , $n = 0 ; public $o = 0 , $p = 0 , $q = 0 , $r = 0 , $s = 0 , $t = 0 , $u = 0 ; public $v = 0 , $w = 0 , $x = 0 , $y = 0 , $z = 0 ;} class Wrapper4 { public $a = 0 , $b = 0 , $c = 0 , $d = 0 , $e = 0 , $f = 0 , $g = 0 ; public $h = 0 , $i = 0 , $j = 0 , $k = 0 , $l = 0 , $m = 0 , $n = 0 ; public $o = 0 , $p = 0 , $q = 0 , $r = 0 , $s = 0 , $t = 0 , $u = 0 ; public $v = 0 , $w = 0 , $x = 0 , $y = 0 , $z = 0 ; public function set ( $k , $v ) { $this -> $k = $v ; } public function get ( $k ) { return $this -> $k ; } public function has ( $k ) { return !empty ( $this -> $k ); }} Schema (1000 mal) Schlüssel "h" bis "t" schreiben Schlüssel "a" bis "z" lesen und schreiben falls diese leer sind Alle Schlüssel nochmal lesen Das Ergebnis: Code: using a new value for all calls array: 0.015790910720825s object: 0.019371101856232s object (fix): 0.011160640716553s wrapper 1: 0.055833201408386s wrapper 2: 0.041082346439362s wrapper 3: 0.019991140365601s wrapper 3 (fix): 0.01124064207077s wrapper 4: 0.036492087841034s using a new created reference as argument for all array-ref: 0.016140930652618s array-arg: 0.0164009308815s object : 0.020071148872375s object (fix): 0.011620669364929s wrapper 1: 0.058123321533203s wrapper 2: 0.042702448368073s wrapper 3: 0.020651180744171s wrapper 3 (fix): 0.011720671653748s wrapper 4: 0.037342131137848s using the same reference as argument for all calls array-ref: 0.012670722007751s array-arg: 0.015990920066833s object: 0.016700940132141s object (fix): 0.0083904719352722s wrapper 1: 0.04807275056839s wrapper 2: 0.016450939178467s wrapper 3: 0.015830910205841s wrapper 3 (fix): 0.0071604084968567s wrapper 4: 0.028211607933044s using the same reference for all calls (global) array: 0.012590732574463s object: 0.016200919151306s object (fix): 0.0080104613304138s wrapper 1: 0.050002858638763s wrapper 2: 0.016260931491852s wrapper 3: 0.01558089017868s wrapper 3 (fix): 0.0068503999710083s wrapper 4: 0.030301728248596s System: AMD Phenom 2 x4 @3.2 ghz PHP 5.5.9 (cli) (built: Feb 5 2014 13:02:39) Beobachtung: 1. Array (lesen/schreiben in etwa gleich mit Objekten, Iteration um einiges schneller) 2. Objekt mit vordefinierten Attributen (dynamischer Zugriff langsamer, hardcoded schneller als Array!) 3. Leeres Objekt (dynamischer Zugriff langsamer, hardcoded schneller als Array!) 4. Objekt das sich mittels "magic" Methoden selbst modifiziert (nach wiederholter Verwendung mit leeren Objekten identisch) 5. Objekt mit getter/setter Methoden 6. Objekt mit "magic" Methoden und internem Array zum speichern der Daten Bemerkenswertes: Getter und setter Methoden sind schneller als __get() und __set()! (Hätte ich nicht gedacht) Wenn man keinen dynamischen Zugriff auf die Attribute braucht sind simple Objekte bei wiederholter Verwendung fast doppelt so schnell als Arrays (!!!) IteratorAggregate stinkt richtig ab im Vergleich zu simplen Objekten/Arrays (War aber zu erwarten) Fazit: Im Grunde kann man sagen, dass es keine große Rolle spielt ob man einen Array oder ein Objekt verwendet, solange man nicht versucht die Attribute irgendwie zu "emulieren" (u.a. auch durch getter/setter). Bei überwiegend dynamischen Zugriff (Schlüssel ist eine Variable): Array Bei überwiegend direktem Zugriff (Schlüssel ist konstant [egal ob vordefiniert oder nicht]): Objekt Ein "netter" Nebeneffekt: PHP: class Foo { private $bar = 'whops' ;} $foo = new Foo ;foreach ( $foo as $val ) print $val ; // whops + Multi-Zitat Zitieren
#2 27. Mai 2014 AW: Assoziatives-Array vs. Object - Benchmark bei der auswerting sind array ca 10-15% schneller als objekte (0.019 zu 0.016s), die ressourcen vermutlich auch. je nach dem wie viele arrays oder objecte genutzt werden summiert sich das dann am ende doch auch? + Multi-Zitat Zitieren
#3 27. Mai 2014 Zuletzt bearbeitet: 27. Mai 2014 AW: Assoziatives-Array vs. Object - Benchmark Objekte und Arrays nutzen intern die selben Datenstrukturen (HashTable), doch haben Objekte noch einiges mehr an Daten. Ein Objekt setzt sich aus folgendem zusammen: Eine Referenz zur Klasse Eine Liste mit Attributen (HashTable wie in einem Array) Eine weitere Liste mit Attributen für den optimierten Zugriff (deshalb ist der hardcoded Zugriff auf Attribute schneller als bei Arrays). Eine weitere HashTable für "guards" (um in __set() / __get() Rekursionen zu vermeiden). Wie viel Bytes ein Objekt nun mehr konsumiert als ein Array kann ich dir nicht sagen. Sollte sich aber in Grenzen halten. Nach überfliegen des Codes: 3 Pointer á 4 Byte + sizeof(HashTable) + (Ein paar HashTable Buckets) + sizeof(zend_class_entry) Methoden werden btw. nicht beim Objekt gespeichert. ** php-src/Zend/zend.h at master · php/php-src · GitHub ** php-src/Zend/zend.h at master · php/php-src · GitHub + Multi-Zitat Zitieren