yii绑定onEndRequest事件的bug

yii在CListIterator中使用引用,导致迭代在特殊情况下会出现BUG

public function actionIndex()
{
    $data = array('a', 'b', 'c');
    $a = new CList($data);
    foreach ($a as $k => $v) {
        if ($k == 0) {
            unset($a[0]);
        }
        echo $v;
    }
}

如果预先不知道这个情况,很容易出现问题,框架中也有这个问题,看一段代码:

public function setGlobalState($key,$value,$defaultValue=null)
{
    // ...

    if($this->_stateChanged!==$changed)
        $this->attachEventHandler('onEndRequest',array($this,'saveGlobalState'));
}

// ...

/**
* Saves the global state data into persistent storage.
* @see getStatePersister
* @throws CException if the state persister is not available
*/
public function saveGlobalState()
{
    if($this->_stateChanged)
    {
        $this->_stateChanged=false;
        $this->detachEventHandler('onEndRequest',array($this,'saveGlobalState'));
        $this->getStatePersister()->save($this->_globalState);
    }
}

public function raiseEvent($name,$event)
{
    $name=strtolower($name);
    if(isset($this->_e[$name]))
    {
        foreach($this->_e[$name] as $handler)
        {
            // ...
        }
    }
    // ...
}

当runtime目录被清空时,onEndRequest事件触发saveGlobalState动作,在操作的过程中却又解除了saveGlobalState动作的绑定。这会导致raiseEvent事件的时候,原来N个动作变成N-1个动作,但是计算器还是N个,就会下标越界。

向官方提交了这个BUG,想修正的话可以先注释掉这行:

    $this->detachEventHandler('onEndRequest',array($this,'saveGlobalState'));

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据