I'm trying to create a method that will allow me to set properties within a class using the setVal() function, if the user is trying to set the value from outside the class without using the 'forceSet' function then it will throw an exception.
The problem is that its throwing an exception even if the $forceSet is true. If i set the property manually in the class to have private access then everything works fine, but this is not an option as I wish to be able to set various properties in this class dynamically.
class test
{
private $_allowedCols = array('title', 'name', 'surname');
public function __set($n,$v)
{
$this->setVal($n, $v);
}
public function setVal($name, $value, $forceSet=false)
{
if (!$forceSet && !in_array($this->_allowedCols, $name))
{
throw new Exception('cant set value');
}
$this->$name = $value;
}
}
$b = new test;
$b->setVal('blah', 'test', true);
print_r($b);
exit;
What I want to be able to do is set all the values from a $_POST into properties in the object. I want to check against the $_allowedCols to make sure only values I want are being put into the object but sometimes I might want to force values in from the code that aren't in the $_allowedCols.
Any ideas?
true
: - huysentruitw 2012-04-04 18:54
The hacks will work but it might be cleaner to use an internal array. Something like:
class test
{
private $data = array();
public function __set($n,$v)
{
if (isset($this->data[$n])) return $this->data[$n] = $v;
throw new Exception('cant set value');
}
public function __get($n)
{
if (isset($this->data[$n])) return $this->data[$n];
throw new Exception('cant retrieve value');
}
public function setVal($name, $value)
{
$this->data[$name] = $value;
}
}
But if you want to stick with your approach then:
class test
{
private $forceFlag = false;
public function __set($name,$value)
{
if ($this->forceFlag) return $this->$name = $value;
throw new Exception('cant set value');
}
public function setVal($name, $value)
{
$this->forceFlag = true;
$this->$name = $value;
$this->forceFlag = false;
}
}
If you look at the stack trace of your exception, you'll notice the call to set __set
is being triggered by this line:
$this->$name = $value;
Then in __set
, it does $this->setVal($n, $v)
, which uses the default value of false, and thus throws the exception. To fix this, you can modify your call in __set
to be:
$this->setVal($n, $v, true);
With the above code, this line:
$this->$name = $value;
...invokes:
test::__set('blah', 'test');
...because test::$blah
is undefined, which in turn invokes:
test::setVal('blah', 'test', false);
A possible, yet not perfect, workaround is this:
public function setVal($name, $value, $forceSet=false)
{
if (!$forceSet && isset($value))
{
throw new Exception('cant set value');
}
$this->$name = null;
$this->$name = $value;
}
Although I'm not sure what the point of your code is.
After testing so many options .. the is the one that works the best for me
I chose this because
__set
and __get
can easily be overriding by extending class Code :
abstract class Hashtable
{
final $hashTable = array() ;
final function __set($n,$v)
{
return false ;
}
final function __get($n)
{
return @$this->hashTable[$n] ;
}
final function _set($n, $v)
{
$this->hashTable[$n] = $v ;
}
}
class Test extends Hashtable {} ;
$b = new Test();
$b->_set("bar","foo",true);
$b->_set("hello","world",true);
//$b->setVal("very","bad"); // false
$b->bar = "fail" ;
var_dump($b,$b->bar);
Output
object(Test)[1]
public 'hashTable' =>
array
'bar' => string 'foo' (length=3)
'hello' => string 'world' (length=5)
string 'foo' (length=3)
I hope this helps
Thanks
:)
$b->bar
simply by doing $b->bar = "fail"
huysentruitw 2012-04-04 19:07
It looks like you write much code for a functionality PHP offers out of the box:
$b = new test;
$b->blah = 'test';
print_r($b);
You don't need __set
for this, nor the setVal
(ue) function.
However when you want to control the access, you need to ensure that you're not binding it to members. Instead store it inside of a map as a private member:
class test
{
private $values;
public function __set($n,$v)
{
$this->setVal($n, $v);
}
public function setVal($name, $value, $forceSet=false)
{
if (!$forceSet)
{
throw new Exception('cant set value');
}
$this->values[$name] = $value;
}
}
This ensures, that a member exists that is set, so that __set
is not triggered again.
$this->$name = $value;
will trigger the__set
method which in case will trigger thesetVal
with$forceSet=false
huysentruitw 2012-04-04 18:53