1

我正在尝试创建一个方法,该方法允许我使用 setVal() 函数在类中设置属性,如果用户试图从类外部设置值而不使用“forceSet”函数,那么它将抛出一个例外。

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

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 中的值。

有任何想法吗?

4

5 回答 5

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;
    }
}
于 2012-04-04T19:11:37.593 回答
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不会再次触发。

于 2012-04-04T19:08:41.977 回答
0

如果您查看异常的堆栈跟踪,您会注意到对 set 的调用__set是由这一行触发的:

$this->$name = $value;

然后在 中__set,它$this->setVal($n, $v)使用默认值 false,从而引发异常。要解决此问题,您可以将调用修改__set为:

$this->setVal($n, $v, true);
于 2012-04-04T18:53:58.210 回答
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;
}

虽然我不确定你的代码的意义是什么。

于 2012-04-04T18:53:58.863 回答
0

在测试了这么多选项之后..这是最适合我的选项

我选择这个是因为

  1. 使用异常会终止整个脚本,或者必须在声明值时捕获异常
  2. __set并且__get可以通过扩展类轻松覆盖
  3. 可与多个类一起使用的实现
  4. 什么能够直接使用 Object 而无需添加另一个 getter 方法
  5. 锁定可能导致冲突
  6. 该脚本不会改变您现有的应用程序结构
  7. 可以与单例一起使用..

代码 :

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)

我希望这有帮助

谢谢

:)

于 2012-04-04T18:57:30.517 回答