I think its quite a simple question but not sure.
I have a class:
<?PHP
class PropertyTest {
private $data = array();
public function __set($name, $value) {
$this->data[$name] = $value;
}
public function __get($name) {
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
$trace = debug_backtrace();
trigger_error(
'Undefined property via __get(): ' . $name .
' in ' . $trace[0]['file'] .
' on line ' . $trace[0]['line'],
E_USER_NOTICE);
return null;
}
public function __isset($name) {
echo "Is '$name' set?\n";
return isset($this->data[$name]);
}
public function __unset($name) {
echo "Unsetting '$name'\n";
unset($this->data[$name]);
}
public function getHidden() {
return $this->hidden;
}
}
?>
Not sure why but the 'code' block is annoying as hell, anyway.
Just the basic magic get set really. But when I change the __get
to pass by reference I cant do this anymore:
$object->$variableName = $variableValue;
I'm not sure why although I assume because it checks if it exists but since it has to return something by reference it will fail to do so if it doesn't exists to begin with. The set function wont be called probably and even if I return a fake value it would never call the set function cause it 'already exists/has a value'.
Am I understanding this correctly? If so, Is there a work around? If not how does it work and is there a workaround?
Unless I'm missing something it's working fine for me
<?php
class PropertyTest
{
private $data = array();
public function __set($name, $value)
{
$this->data[$name] = $value;
}
public function &__get($name)
{
if(array_key_exists($name, $this->data))
return $this->data[$name];
return null;
}
public function __isset($name)
{
return isset($this->data[$name]);
}
public function __unset($name)
{
unset($this->data[$name]);
}
public function getHidden()
{
return $this->hidden;
}
}
$oPropTest = new PropertyTest();
$sField = 'my-field';
$oPropTest->$sField = 5;
var_dump($oPropTest);
Outputs:
bash-3.2$ php test-get-set.php
object(PropertyTest)#1 (1) {
["data":"PropertyTest":private]=>
array(1) {
["my-field"]=>
int(5)
}
}
One tweak I'd suggest for your __get
implementation is to leverage the __isset
method rather than re-implement the check (doing it 2 different ways as you are)
public function __get($name)
{
if($this->__isset($name))
return $this->data[$name];
return null;
}
Regarding the idea of return-by-reference from __get
; it will work, but be useless on anything but public attributes, since private and protected attributes won't be settable directly through a reference outside the class scope.
$oPropTest = new PropertyTest();
$sField = 'my-field';
$oPropTest->$sField = 5; // sets $oPropTest->my-field to 5 (effectively)
$iRef = $oPropTest->$sField; // $iRef is a reference to $oPropTest->my-field
$iRef = 6; // this will not set $oPropTest->my-field since it's private