I have a huge amount of PHP objects for a neural network for which I have to iterate over and perform some maths on. I was wondering if I would be better off using an associ
For anybody who is still interested in this question :) I ran Quazzle code on PHP 7.1 Ubuntu x64 and got this answer:
arrays: 0.24848890304565
memory: 444920
Array
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
arrays: 0.23238587379456
memory: 164512
SomeClass Object
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
arrays: 0.24422693252563
memory: 484416
stdClass Object
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
Array take 4(!) the memory than class object.
Class object marginally faster.
stdClass still evil © magallanes :)
You haven't shown us the code for how $object->value
works, as it could be that backend it is an array in which case theoretically using an array would be faster as it involves one less function call. The cost of doing the lookup will probably be huge compared to the function call. If it is a variable, there is going to be very little diffrence as objects and arrays in PHP have a very similar implementation.
If you are looking at optimizations, you will need to profile to check where the majority of the time is being used. I suspect that changing objects to arrays will make no major difference.
You can always check the PHP-source code for micro-performance-features like that.
But at a first glance, no doing ['value'] will not be faster because PHP needs to do a Lookup on where to find ['value'] even thougn a hashtable lookup should be O(1), that's not guaranteed. There's more overhead when you use Text-index.
If the object only contains 1 variables that you need to access which is value, there's more overhead in using an object.
I used this code for "profiling" (1000 instances, 1000.000 reads/writes):
function p($i) {
echo '<pre>';
print_r($i);
echo '</pre>';
}
$t0 = microtime(true);
for ($i=0; $i<1000; $i++) {
$z = array();
for ($j=0; $j<1000; $j++) {
$z['aaa'] = 'aaa';
$z['bbb'] = 'bbb';
$z['ccc'] = $z['aaa'].$z['bbb'];
}
}
echo '<p>arrays: '.(microtime(true) - $t0);
p($z);
$t0 = microtime(true);
for ($i=0; $i<1000; $i++) {
$z = (object) null;
for ($j=0; $j<1000; $j++) {
$z->aaa = 'aaa';
$z->bbb = 'bbb';
$z->ccc = $z->aaa.$z->bbb;
}
}
echo '<p>obj: '.(microtime(true) - $t0);
p($z);
echo '<p> phpversion '.phpversion();
It outputs in my LINUX hosting this stuff:
arrays: 1.1085488796234
Array
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
obj: 1.2824709415436
stdClass Object
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
phpversion 5.2.17
so in a conclusion: objects are slower even on PHP 5.2. Don't use objects unless you really need their oop features.
If Arrays and Classs are the same performance, I think use objects of predefined classes for storing/passing business data would make our program more logic and the code more readability.
Today, with modern ide like Eclipse, Netbean ... it's very convenient to know what info an objects (of predefined class) is carrying but arrays are not so
Eg: With array
function registerCourse(array $student) {
// Right here I don't know how a $student look like unless doing a print_r() or var_dump()
....
}
With object
class Studen {
private $_name, $_age;
public function getAge() {}
public function getName() {}
..
}
function registerCourse(Studen $student) {
// Right here I just Ctrl+Space $student or click "Student" and I know I can get name or age from it
...
}
Well I got curious today based off of @magallanes benchmark, so I expanded it a bit. I upped some of the for loops to really highlight the gaps between things. This is running on Apache 2.4, mod_php, and PHP 7.2.
Here's a summary table to make the results easier:
+---------------------------+---------+-----------------+
| Test | Memory | Time |
+---------------------------+---------+-----------------+
| Array | 2305848 | 9.5637300014496 |
| stdClass | 2505824 | 11.212271928787 |
| SomeClass | 963640 | 11.558017015457 | <-- *
| AnotherClass | 2563136 | 10.872401237488 |
| SetterClass | 905848 | 59.879059791565 |
| SetterClassDefineReturn | 905792 | 60.484427213669 |
| SetterClassSetFromParam | 745792 | 62.783381223679 |
| SetterClassSetKeyAndParam | 745824 | 72.155715942383 |
+---------------------------+---------+-----------------+
* - Winner winner chicken dinner
Below is the modified script. I wanted to test setting properties with methods and defining types. I was very surprised to find that using setter methods adds a significant hit to the code. Now granted this is a very very specific performance test where many apps will not even hit this. But if you have a site that handles 1000/reqs/second with 1000 classes that are used with 1000s of objects, you can see how this may affect performance.
<?php
set_time_limit(500);
class SomeClass {
public $aaa;
public $bbb;
public $ccc;
}
class AnotherClass {
}
class SetterClass {
public $aaa;
public $bbb;
public $ccc;
public function setAAA() {
$this->aaa = 'aaa';
}
public function setBBB() {
$this->bbb = 'bbb';
}
public function setCCC() {
$this->ccc = $this->aaa.$this->bbb;
}
}
class SetterClassDefineReturn {
public $aaa;
public $bbb;
public $ccc;
public function setAAA():void {
$this->aaa = 'aaa';
}
public function setBBB():void {
$this->bbb = 'bbb';
}
public function setCCC():void {
$this->ccc = $this->aaa.$this->bbb;
}
}
class SetterClassSetFromParam {
public $aaa;
public $bbb;
public $ccc;
public function setAAA(string $val): void {
$this->aaa = $val;
}
public function setBBB(string $val): void {
$this->bbb = $val;
}
public function setCCC(string $val): void {
$this->ccc = $val;
}
}
class SetterClassSetKeyAndParam {
public $aaa;
public $bbb;
public $ccc;
public function set(string $key, string $val): void {
$this->{$key} = $val;
}
}
function p($i) {
echo '<pre>';
print_r($i);
echo '</pre>';
echo '<hr>';
}
$t0 = microtime(true);
$arraysOf=[];
$inicio=memory_get_usage();
for ($i=0; $i<5000; $i++) {
$z = new SomeClass();
for ($j=0; $j<5000; $j++) {
$z->aaa = 'aaa';
$z->bbb = 'bbb';
$z->ccc = $z->aaa.$z->bbb;
}
$arraysOf[]=$z;
}
$fin=memory_get_usage();
echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
echo '<p>Memory: '.($fin-$inicio).'</p>';
p($z);
$t0 = microtime(true);
$arraysOf=[];
$inicio=memory_get_usage();
for ($i=0; $i<5000; $i++) {
$z = new AnotherClass();
for ($j=0; $j<5000; $j++) {
$z->aaa = 'aaa';
$z->bbb = 'bbb';
$z->ccc = $z->aaa.$z->bbb;
}
$arraysOf[]=$z;
}
$fin=memory_get_usage();
echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
echo '<p>Memory: '.($fin-$inicio).'</p>';
p($z);
$t0 = microtime(true);
$arraysOf=[];
$inicio=memory_get_usage();
for ($i=0; $i<5000; $i++) {
$z = new SetterClass();
for ($j=0; $j<5000; $j++) {
$z->setAAA();
$z->setBBB();
$z->setCCC();
}
$arraysOf[]=$z;
}
$fin=memory_get_usage();
echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
echo '<p>Memory: '.($fin-$inicio).'</p>';
p($z);
$t0 = microtime(true);
$arraysOf=[];
$inicio=memory_get_usage();
for ($i=0; $i<5000; $i++) {
$z = new SetterClassDefineReturn();
for ($j=0; $j<5000; $j++) {
$z->setAAA();
$z->setBBB();
$z->setCCC();
}
$arraysOf[]=$z;
}
$fin=memory_get_usage();
echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
echo '<p>Memory: '.($fin-$inicio).'</p>';
p($z);
$t0 = microtime(true);
$arraysOf=[];
$inicio=memory_get_usage();
for ($i=0; $i<5000; $i++) {
$z = new SetterClassSetFromParam();
for ($j=0; $j<5000; $j++) {
$z->setAAA('aaa');
$z->setBBB('bbb');
$z->setCCC('aaabbb');
}
$arraysOf[]=$z;
}
$fin=memory_get_usage();
echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
echo '<p>Memory: '.($fin-$inicio).'</p>';
p($z);
$t0 = microtime(true);
$arraysOf=[];
$inicio=memory_get_usage();
for ($i=0; $i<5000; $i++) {
$z = new SetterClassSetKeyAndParam();
for ($j=0; $j<5000; $j++) {
$z->set('aaa', 'aaa');
$z->set('bbb', 'bbb');
$z->set('ccc', 'aaabbb');
}
$arraysOf[]=$z;
}
$fin=memory_get_usage();
echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
echo '<p>Memory: '.($fin-$inicio).'</p>';
p($z);
$t0 = microtime(true);
$arraysOf=[];
$inicio=memory_get_usage();
for ($i=0; $i<5000; $i++) {
$z = new stdClass();
for ($j=0; $j<5000; $j++) {
$z->aaa = 'aaa';
$z->bbb = 'bbb';
$z->ccc = $z->aaa.$z->bbb;
}
$arraysOf[]=$z;
}
$fin=memory_get_usage();
echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
echo '<p>Memory: '.($fin-$inicio).'</p>';
p($z);
$t0 = microtime(true);
$arraysOf=[];
$inicio=memory_get_usage();
for ($i=0; $i<5000; $i++) {
$z = [];
for ($j=0; $j<5000; $j++) {
$z['aaa'] = 'aaa';
$z['bbb'] = 'bbb';
$z['ccc'] = $z['aaa'].$z['bbb'];
}
$arraysOf[]=$z;
}
$fin=memory_get_usage();
echo '<p>Time Taken (seconds): '.(microtime(true) - $t0).'</p>';
echo '<p>Memory: '.($fin-$inicio).'</p>';
p($z);
And here's the results:
Time Taken (seconds): 11.558017015457
Memory: 963640
SomeClass Object
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
-----
Time Taken (seconds): 10.872401237488
Memory: 2563136
AnotherClass Object
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
----
Time Taken (seconds): 59.879059791565
Memory: 905848
SetterClass Object
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
----
Time Taken (seconds): 60.484427213669
Memory: 905792
SetterClassDefineReturn Object
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
----
Time Taken (seconds): 62.783381223679
Memory: 745792
SetterClassSetFromParam Object
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
----
Time Taken (seconds): 72.155715942383
Memory: 745824
SetterClassSetKeyAndParam Object
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
----
Time Taken (seconds): 11.212271928787
Memory: 2505824
stdClass Object
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)
----
Time Taken (seconds): 9.5637300014496
Memory: 2305848
Array
(
[aaa] => aaa
[bbb] => bbb
[ccc] => aaabbb
)