We see that the count hinges on the NULL status of the
_totalRecords
property. So it looks like a bug in core code. Am I reading this correctly?
Whether to interpret said behaviour as bug or feature, lies in the eyes of the beholder.
This behaviour is not 1.4 specific, btw; it works the same way up to the current CE version (1.8.1).
public function getSize()
{
$this->load();
if (is_null($this->_totalRecords)) {
$this->_totalRecords = count($this->getItems());
}
return intval($this->_totalRecords);
}
Most people for sure expect a method named getSize()
to always return the current size, so they may call it a bug, perhaps.
But if you take a closer look at the Varien_Data_Collection
class, you'll notice, that getSize()
is not the only method that looks somewhat.. "weird".
Take the addItem()
and removeItemByKey()
methods, for example.
Why don't they increment/decrement the _totalRecords
property, when getSize()
uses it?
Lazy Loading
The reason for these "weird" behaviours is, that Varien_Data_Collection
basically is designed for the usage of the Lazy Loading pattern. That means, it allows to delay loading of the collection, until the data is really needed.
To accomplish this, Varien_Data_Collection
implements the IteratorAggregate
and Countable
interfaces. Their implementation points are the getIterator()
and count()
methods:
public function getIterator()
{
$this->load();
return new ArrayIterator($this->_items);
}
public function count()
{
$this->load();
return count($this->_items);
}
As you can see, both of these methods call load()
first.
The result of this is, that whenever you use foreach
or the PHP function count()
on the collection, the load()
method automatically will be called first.
Now, for a default Varien_Data_Collection
nothing special will happen, when load()
is called, because load()
only calls loadData()
and loadData()
only returns $this
.
But when it comes to its heavily used child class Varien_Data_Collection_Db
, then the call to load()
will result in loading the collection and setting _totalRecords
to the SQL count
of loaded records.
For performance reasons the collection usually will be loaded once only (if it hasn't been loaded yet).
So you see, depending on which context you use Varien_Data_Collection
in, it perfectly makes sense, why getSize()
behaves this way.
Should I just rely on a call to
count
on the items?
If your collection is not bound to complex or slow I/O, I'd say: yes.
You can simply use:
$n = count($this->_rows->getItems());
Or even this way:
$n = count($this->_rows->getIterator());