Search code examples
yiiframeworksclist

Yii CList error - do not have a method or closure named "setReadOnly"


I have a basic function that is using CList - for some reason I get the following error:

CList and its behaviors do not have a method or closure named "setReadOnly".

My php code

$list = new CList(array('python', 'ruby'));
$anotherList = new Clist(array('php'));
    var_dump($list);
$list->mergeWith($anotherList);
    var_dump($list);
$list->setReadOnly(true); // CList and its behaviors do not have a method or closure named "setReadOnly". 

Can anyone explain why I am getting this error?

P.S i copied this code directly from a recent Yii book... so I am abit puzzled

// Update: added the var_dump before and after the mergeWith()

object(CList)[20]
  private '_d' => 
    array (size=2)
     0 => string 'python' (length=6)
     1 => string 'ruby' (length=4)
  private '_c' => int 2
  private '_r' => boolean false
  private '_e' (CComponent) => null
  private '_m' (CComponent) => null

object(CList)[20]
  private '_d' => 
    array (size=3)
    0 => string 'python' (length=6)
    1 => string 'ruby' (length=4)
    2 => string 'php' (length=3)
  private '_c' => int 3
  private '_r' => boolean false
  private '_e' (CComponent) => null
  private '_m' (CComponent) => null

Solution

  • The CList method setReadOnly() is protected and thus cannot be called from the scope you're using, only from within itself or inheriting classes. See http://php.net/manual/en/language.oop5.visibility.php#example-188.

    However, the CList class allows the list to be set as read only in its constructor

    public function __construct($data=null,$readOnly=false)
    {
        if($data!==null)
        $this->copyFrom($data);
        $this->setReadOnly($readOnly);
    }
    

    So...

    $list = new CList(array('python', 'ruby'), true); // Passing true into the constructor
    $anotherList = new CList(array('php'));
    $list->mergeWith($anotherList);
    

    Results in the error

    CException The list is read only. 
    

    I'm not sure if that's the result you're looking for, but if you want a read only CList that's one way to get it.

    You might think when merging subsequent CLists you could set readonly true at the end, however mergeWith() only merges the _d data array, not the other class variables, so it remains false.

    $list = new CList(array('python', 'ruby'));
    $anotherList = new CList(array('php'));
    $yetAnotherList = new CList(array('javacript'), true);
    
    $list->mergeWith($anotherList);
    $list->mergeWith($yetAnotherList);
    
    var_dump($list); // ["_r":"CList":private]=>bool(false)