[PHP] class object vs array for db table model
Hi everyone, It's been a couple years since I've did a project in PHP. The current project I'm working on is for PHP 5.3 and I noticed a performance issue. Is it just me or is there a BIG difference in performance between class object vs array for PHP 5.3? Below is the sample: class MyTable { private $_id; // int private $_name; // varchar private $_description; // text public function __construct() {} public function getId() { return $this-_id; } public function getName() { return $this-_name; } public function getDescription() { return $this-_description; } public function setId($id) { $this-_id = $id; } public function setName($name) { $this-_name = $name; } public function setDescription($description) { $this-_description = $description; } } $my_table = array ('id' = 'id value', 'name' = 'name value', 'description' = 'long description text'); The above are representations for my table as class and as array, respectively. The only difference is how I represent the results from db: 1) as class object $list = array(); while ($row = $db-fetch($result)) { $my_table = new MyTable(); $my_table-setId($row['id']); $my_table-setName($row['name']); $my_table-setDescription($row['description']); $list[$my_table-getId()] = $my_table; } 2) as table $list = array(); while ($row = $db-fetch($result)) { $my_table['id'] = $row['id']; $my_table['name'] = $row['name']; $my_table['description'] = $row['description']; $list[$my_table['id'] = $my_table; } The performance difference I get is about 1.4 seconds with the array in the lead!!! Does anyone have the same problem? Thanks, Tommy PS: The above executed in 4.2 sec and 1.8 sec (on average) respectively w/o actually showing the results to html, while my ASP.NET project executes it and displays in html in about 2 seconds for all 3684 rows, using class similar to the MyTable. All codes, PHP ASP.NET C#, access the same MySQL DB on the same development box. -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] class object vs array for db table model
On Tue, Oct 12, 2010 at 2:38 AM, Tommy Pham tommy...@gmail.com wrote: Hi everyone, It's been a couple years since I've did a project in PHP. The current project I'm working on is for PHP 5.3 and I noticed a performance issue. Is it just me or is there a BIG difference in performance between class object vs array for PHP 5.3? Below is the sample: class MyTable { private $_id; // int private $_name; // varchar private $_description; // text public function __construct() {} public function getId() { return $this-_id; } public function getName() { return $this-_name; } public function getDescription() { return $this-_description; } public function setId($id) { $this-_id = $id; } public function setName($name) { $this-_name = $name; } public function setDescription($description) { $this-_description = $description; } } $my_table = array ('id' = 'id value', 'name' = 'name value', 'description' = 'long description text'); The above are representations for my table as class and as array, respectively. The only difference is how I represent the results from db: 1) as class object $list = array(); while ($row = $db-fetch($result)) { $my_table = new MyTable(); $my_table-setId($row['id']); $my_table-setName($row['name']); $my_table-setDescription($row['description']); $list[$my_table-getId()] = $my_table; } 2) as table $list = array(); while ($row = $db-fetch($result)) { $my_table['id'] = $row['id']; $my_table['name'] = $row['name']; $my_table['description'] = $row['description']; $list[$my_table['id'] = $my_table; } The performance difference I get is about 1.4 seconds with the array in the lead!!! Does anyone have the same problem? Thanks, Tommy PS: The above executed in 4.2 sec and 1.8 sec (on average) respectively w/o actually showing the results to html, while my ASP.NET project executes it and displays in html in about 2 seconds for all 3684 rows, using class similar to the MyTable. All codes, PHP ASP.NET C#, access the same MySQL DB on the same development box. When you are adding a row as an object you are calling 4 user functions: MyTable::__construct(), MyTable::setId(), MyTable::setName(), and MyTable::setDescription(). This adds some overhead for sure, so you might want to think about passing the row array into the construct and doing away with the setters (at least for the initial instantiations). Something like this... - public function __construct($dataArray=null) { foreach ((array)$dataArray as $rowKey = $rowValue) { $this-$rowKey = $rowValue; } } ==OR== public function __construct($dataArray=null) { // maybe add casting here as well? $this-_id = isset($dataArray['id'])? $dataArray['id']: null; $this-_name = isset($dataArray['name'])? $dataArray['name']: null; $this-_description = isset($dataArray['description'])? $dataArray['description']: null; } ==And instantiate like this== $list = array(); while ($row = $db-fetch($result)) { // I also changed setting the $list's key with $row['id'] instead of using the MyTable getter. $list[$row['id']] = new MyTable($row); } --- I don't know how much faster that will run for you (if at all) but using your method you were calling 5 user functions per result set from the db (that's the construct, the getter to set the $list key, and 1 for each of the 3 properties of the result) for a total of 18,420 user function calls. With my method I'm calling 1 user function (the construct) for each set, for a total of 3,684 calls. Of course a down-side is that if there's any logic in your setters then that needs to be replicated in your construct. Another method is to use a single object for all 3684 records. Perhaps you can use the built in Iterator interface which lets your class's objects be used as if they were an array for the purposes of foreach loops. http://php.net/manual/en/language.oop5.iterations.php You would set a pointer to the record you wish to use, and your getters and setters would key off that element of the master array. This should be a fast solution, while still giving you the power of encapsulation, getters and setters. Hope that helps! Chris.
Re: [PHP] class object vs array for db table model
On Tue, Oct 12, 2010 at 4:45 AM, chris h chris...@gmail.com wrote: snip When you are adding a row as an object you are calling 4 user functions: MyTable::__construct(), MyTable::setId(), MyTable::setName(), and MyTable::setDescription(). This adds some overhead for sure, so you might want to think about passing the row array into the construct and doing away with the setters (at least for the initial instantiations). Something like this... - public function __construct($dataArray=null) { foreach ((array)$dataArray as $rowKey = $rowValue) { $this-$rowKey = $rowValue; } } ==OR== public function __construct($dataArray=null) { // maybe add casting here as well? $this-_id = isset($dataArray['id'])? $dataArray['id']: null; $this-_name = isset($dataArray['name'])? $dataArray['name']: null; $this-_description = isset($dataArray['description'])? $dataArray['description']: null; } ==And instantiate like this== $list = array(); while ($row = $db-fetch($result)) { // I also changed setting the $list's key with $row['id'] instead of using the MyTable getter. $list[$row['id']] = new MyTable($row); } --- I don't know how much faster that will run for you (if at all) but using your method you were calling 5 user functions per result set from the db (that's the construct, the getter to set the $list key, and 1 for each of the 3 properties of the result) for a total of 18,420 user function calls. With my method I'm calling 1 user function (the construct) for each set, for a total of 3,684 calls. Of course a down-side is that if there's any logic in your setters then that needs to be replicated in your construct. Another method is to use a single object for all 3684 records. Perhaps you can use the built in Iterator interface which lets your class's objects be used as if they were an array for the purposes of foreach loops. http://php.net/manual/en/language.oop5.iterations.php You would set a pointer to the record you wish to use, and your getters and setters would key off that element of the master array. This should be a fast solution, while still giving you the power of encapsulation, getters and setters. Hope that helps! Chris. Hi Chris, Thanks for the reply. The sample I made is just for simplicity and comparison. As for function calling 'get's, I think the speed would come out to be same in your sample since you're doing isset() checking. My actual class is more sophisticated having the psuedo overloading as you mentioned. The class is generated from a PHP class builder - to save on typing - I made a long time ago with some minor update. Anyway, I was frustrated as to why my code took so long to execute and had to dig deep. As it turns out, I had xdebug loaded with all options on ... lol. Removed the extension and all is good in the world. The script runs in less than 150ms :D!!! Thanks, Tommy PS: This is what I get for not coding in PHP so long ... -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] class object vs array for db table model
hehe that's pretty funny; also funny oversight of mine in regards to isset()... so I guess we're both comedians today? ;-) Glad you got that worked out Tommy! Chris. On Tue, Oct 12, 2010 at 8:46 AM, Tommy Pham tommy...@gmail.com wrote: On Tue, Oct 12, 2010 at 4:45 AM, chris h chris...@gmail.com wrote: snip When you are adding a row as an object you are calling 4 user functions: MyTable::__construct(), MyTable::setId(), MyTable::setName(), and MyTable::setDescription(). This adds some overhead for sure, so you might want to think about passing the row array into the construct and doing away with the setters (at least for the initial instantiations). Something like this... - public function __construct($dataArray=null) { foreach ((array)$dataArray as $rowKey = $rowValue) { $this-$rowKey = $rowValue; } } ==OR== public function __construct($dataArray=null) { // maybe add casting here as well? $this-_id = isset($dataArray['id'])? $dataArray['id']: null; $this-_name = isset($dataArray['name'])? $dataArray['name']: null; $this-_description = isset($dataArray['description'])? $dataArray['description']: null; } ==And instantiate like this== $list = array(); while ($row = $db-fetch($result)) { // I also changed setting the $list's key with $row['id'] instead of using the MyTable getter. $list[$row['id']] = new MyTable($row); } --- I don't know how much faster that will run for you (if at all) but using your method you were calling 5 user functions per result set from the db (that's the construct, the getter to set the $list key, and 1 for each of the 3 properties of the result) for a total of 18,420 user function calls. With my method I'm calling 1 user function (the construct) for each set, for a total of 3,684 calls. Of course a down-side is that if there's any logic in your setters then that needs to be replicated in your construct. Another method is to use a single object for all 3684 records. Perhaps you can use the built in Iterator interface which lets your class's objects be used as if they were an array for the purposes of foreach loops. http://php.net/manual/en/language.oop5.iterations.php You would set a pointer to the record you wish to use, and your getters and setters would key off that element of the master array. This should be a fast solution, while still giving you the power of encapsulation, getters and setters. Hope that helps! Chris. Hi Chris, Thanks for the reply. The sample I made is just for simplicity and comparison. As for function calling 'get's, I think the speed would come out to be same in your sample since you're doing isset() checking. My actual class is more sophisticated having the psuedo overloading as you mentioned. The class is generated from a PHP class builder - to save on typing - I made a long time ago with some minor update. Anyway, I was frustrated as to why my code took so long to execute and had to dig deep. As it turns out, I had xdebug loaded with all options on ... lol. Removed the extension and all is good in the world. The script runs in less than 150ms :D!!! Thanks, Tommy PS: This is what I get for not coding in PHP so long ...