[eluser]Unknown[/eluser]
[quote author="RobertX" date="1191216136"]
As a synthesis of everyone's suggestions I came up with this (dropping the valid{$name}() call as it was confusing the issue):
Code:
public function __set( $name, $value )
{
if ( $name[0] == '_' || $name == 'config' || $name == 'input' || $name == 'benchmark' || $name == 'uri' || $name == 'output' || $name == 'lang' || $name == 'load' )
{
$this->$name = $value;
}
else
{
$this->data[$name] = $value;
}
return true;
}
But of course that's too brittle to be used in anger.
I think that dynamically creating class "variables" at runtime using __set() and a private array just won't work reliably when you're extending a base class. A PHP problem, not a CI problem.[/quote]
Hey RobertX. I just got done fighting with this little issue as well. It was a pain to try and figure out. You're initial thought process wasn't too far off actually. You were right that CI is trying to call a bunch of internal assignments that are in fact getting passed to your __set method. It didn't necessarily have anything to do with you adding "valid" like you mentioned though.
I think you and I are actually trying to do similar things. And although your post was from last September, I'm assuming other individuals may be running across this issue so I figured I'd share my "workaround". Hopefully maybe there's a way to fix this in the CI core that would more easily allow the use of the magic __set method. Although, the workaround I came up with isn't too bad. The code that you have above isn't far from what I came up with, but you limit your code to only core CI libraries. If you end up adding additional libraries for your application, the above code will fail. If you're using the __set method to update a private array then I'm assuming you know what fields will be in that array. If you do, then you can easily say something like
Code:
public function __set( $name, $value )
{
if(in_array($name,$this->data))
$this->data[$name] = $value
else
$this->$name = $value
endif;
}
and I believe that would fix your problem. Then...if the $name parameter exists as part of your private $data array then it would update the value, if not we'd assume is was an internal CI call and just let it do it's thing. Does this all make sense?
Here's how I could see this playing out. Just off the top of my head - not tested.
Code:
class MY_Model extends Model
{
private $this->table;
private $this->columns;
private $this->data;
public function __construct()
{
parent::Model
$this->table = strtolower(substr(get_class($this), 0, -5));
$this->columns = $this->db->list_fields($this->table);
}
public function __get($var)
{
return $this->data[$var];
}
public function __set($var, $val)
{
if(in_array($var,$this->columns)):
$this->data[$var] = $val;
else:
$this->$var = $val;
endif;
}
}
Obviously there would be more to that, but I think that's a good start.
Hope this helps someone, it definitely gave me fits for a couple of days. I'll try to take a look at the core CI code and see if there isn't a way to make this a little easier.