Re: class object vs array for db table model

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Oct 12, 2010 at 2:38 AM, Tommy Pham <tommyhp2@xxxxxxxxx> 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.

[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux