删除项目后,Magento Varien_Data_Collection返回错误的大小

Ric*_*ski 2 magento-1.4

我正在运行Magento 1.4,但也在1.7中验证了这个问题.

使用实例Varien_Data_Collection提供了使用Varien_Data_Collection::removeItemByKey.在我的情况下,我正在从集合中删除项目,然后尝试获取该集合的更新大小,如下所示:

$body=$this->getTable()->getBody();

echo $body->getHeight(); // Outputs 25

$body->deleteRow(1);

echo $body->getHeight(); // Still outputs 25

...

My_Model_Body_Class extends Mage_Core_Model_Abstract {

  /* @var $_rows Varien_Data_Collection */
  protected $_rows;

  public function deleteRow($index) {
    $this->_rows->removeItemByKey($index);

    return $this;
  }

  public function getHeight() {
    return $this->_rows->getSize();
  }

}

...
Run Code Online (Sandbox Code Playgroud)

代码限制简洁.

因此,如果您调用我的deleteRow方法,该项目实际上将从集合中删除,但后续调用以获取该集合的大小将始终返回原始计数.因此,如果我在集合中有25个项目,并删除1,那么getSize对集合的调用将返回25.

我将其追溯到父类,在Varien_Data_Collection::getSize:

/**
 * Retrieve collection all items count
 *
 * @return int
 */
public function getSize()
{
    $this->load();
    if (is_null($this->_totalRecords)) {
        $this->_totalRecords = count($this->getItems());
    }
    return intval($this->_totalRecords);
}
Run Code Online (Sandbox Code Playgroud)

我们看到计数取决于_totalRecords属性的NULL状态.所以它看起来像核心代码中的一个错误.我读得对吗?我应该只依靠对count物品的电话吗?

Jür*_*len 6

我们看到计数取决于_totalRecords 属性的NULL状态.所以它看起来像核心代码中的一个错误.我读得对吗?

是否将所述行为解释为错误或特征,取决于旁观者的眼睛.

这个行为不是1.4具体的,顺便说一下; 它的工作方式与当前的CE版本(1.8.1)相同.

public function getSize()
{
    $this->load();
    if (is_null($this->_totalRecords)) {
        $this->_totalRecords = count($this->getItems());
    }
    return intval($this->_totalRecords);
}
Run Code Online (Sandbox Code Playgroud)

大多数人肯定希望一个名为getSize()always 的方法总是返回当前大小,所以他们可能会把它称为bug.

但是如果你仔细看看这个Varien_Data_Collection课程,你会注意到,这getSize()不是唯一看起来有点像......"怪异"的方法.

例如,采用addItem()removeItemByKey()方法.

_totalRecordsgetSize()使用它时,为什么不增加/减少属性?

延迟加载

这些"怪异"行为的原因是,它Varien_Data_Collection基本上是为使用延迟加载模式而设计的.这意味着,它允许延迟加载集合,直到真正需要数据.

要实现此目的,请Varien_Data_Collection实现IteratorAggregateCountable接口.他们的实施要点是getIterator()count()方法:

public function getIterator()
{
    $this->load();
    return new ArrayIterator($this->_items);
}

public function count()
{
    $this->load();
    return count($this->_items);
}
Run Code Online (Sandbox Code Playgroud)

如您所见,这两种方法都load()首先调用.

结果是,无论何时使用集合上的foreachPHP函数count(),load()都会自动调用该方法.

现在,对于默认Varien_Data_Collection情况,load()调用时不会发生任何特殊情况,因为load()只有调用loadData()loadData()只返回$this.

但是当涉及到其使用频繁的子类时Varien_Data_Collection_Db,调用load()将导致加载集合并设置_totalRecords为已count加载记录的SQL .

出于性能原因,集合通常仅加载一次(如果尚未加载).

所以你看,根据你使用的上下文Varien_Data_Collection,它完全有意义,为什么getSize()这样做.

我应该只依靠对count物品的电话吗?

如果您的收藏不受复杂或缓慢的I/O限制,我会说:是的.

你可以简单地使用:

$n = count($this->_rows->getItems());
Run Code Online (Sandbox Code Playgroud)

甚至这样:

$n = count($this->_rows->getIterator());
Run Code Online (Sandbox Code Playgroud)