2012-04-04 39 views
1

我正在尝试创建一个方法,该方法允许我使用setVal()函数设置类中的属性,如果用户试图从类外部设置值而不使用'forceSet'函数然后它会抛出一个异常。在php中覆盖__set魔术功能

问题是,即使$ forceSet为true,它也会抛出一个异常。如果我在类中手动设置属性以便私人访问,那么一切正常,但这不是一个选项,因为我希望能够动态地在这个类中设置各种属性。

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; 

我想要做的就是将$ _POST的所有值设置为对象中的属性。我想检查$ _allowedCols以确保只有我想要的值被放入对象中,但有时我可能想要强制值来自不在$ _allowedCols中的代码。

任何想法?

$this->$name = $value; 

然后在__set,它$this->setVal($n, $v),它使用默认:

+1

这条线SETVAL'$此 - > $名称= $价值;'会触发'__set'方法以防万一使用'$ forceSet = false'触发setVal' – 2012-04-04 18:53:09

+1

用bool保护属性无论如何都是无保护的。你应该找到一个更好的实现你想达到的目标。想象一下,在“用户”知道他需要将第三个参数设置为“true”之前需要多长时间:) – 2012-04-04 18:54:34

+0

虽然我不愿意投票,但是显着改变你的问题令人不悦,并且使得回答相当混乱,因为大部分他们现在处理完全不同的事情。 – Cerad 2012-04-04 21:01:06

回答

1

黑客可以工作,但使用内部阵列可能更干净。喜欢的东西:

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; 
    } 
} 

但是如果你想用你的方法坚持那么:

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; 
    } 
} 
+0

你的第二个approuch没有考虑到$ forceSet函数参数 – 2012-04-04 19:30:50

+0

糟糕。使用这种方法不需要forceSet。意外地把它放进去。安全地说,任何时候setval被调用,然后用户真的想要设置它。 – Cerad 2012-04-04 19:34:59

0

如果你看一下你的异常的堆栈跟踪,你会发现调用设置__set是由该行触发值为false,从而引发异常。为了解决这个问题,你可以修改您的通话中__set是:

$this->setVal($n, $v, true); 
0

与上面的代码,该行:

$this->$name = $value; 

...调用:

test::__set('blah', 'test'); 

..因为test::$blah未定义,因此调用:

test::setVal('blah', 'test', false); 

可能的,但不是完美的,解决方法是这样的:

public function setVal($name, $value, $forceSet=false) 
{ 
    if (!$forceSet && isset($value)) 
    { 
     throw new Exception('cant set value'); 
    } 
    $this->$name = null; 
    $this->$name = $value; 
} 

虽然我不知道你的代码的点是什么。

0

测试这么多的选择后..的是工作最适合我

我选择了这个,因为

  1. 使用异常的终止整个脚本或一个已经赶上例外任何时间一个的值被声明
  2. __set__get可以很容易地通过扩展类
  3. 实现可以替代在与多个类
  4. 使用
  5. 能够使用对象是什么,直接,而无需添加其他getter方法
  6. 锁定可能会导致冲突
  7. 脚本不会改变现有的应用程序结构
  8. 可与辛格尔顿使用..

代码:

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); 

输出

object(Test)[1] 
    public 'hashTable' => 
    array 
     'bar' => string 'foo' (length=3) 
     'hello' => string 'world' (length=5) 
string 'foo' (length=3) 

我希望这有助于

感谢

:)

+0

您仍可以简单地通过执行'$ b-> bar =“fail”覆盖'$ b-> bar' – 2012-04-04 19:07:30

+0

更正..您对新方法有何看法? – Baba 2012-04-04 19:45:26

0

它看起来像你写很多代码的功能PHP提供开箱即用:

$b = new test; 
$b->blah = 'test'; 
print_r($b); 

你不需要__set这一点,也不是setVal(UE)的功能。

但是,当你想控制访问时,你需要确保你没有绑定到成员。相反,它的地图内存储的私有成员:

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; 
    } 
} 

这确保,一个成员存在设置,使__set不会再次触发。