3

我通过利用__get魔法方法来定义当一个不存在的属性被访问时会发生什么。

所以如果$property->bla不存在我会得到null

return (isset($this->$name)) ? $this->$name : null;

$property->bla->bla但是当我知道$property->bla不存在时,我想抛出并捕获错误。

我会在return (isset($this->$name)) ? $this->$name : null;下面得到这个错误,

<b>Notice</b>:  Trying to get property of non-object in...

所以我throw and catch在课堂上使用错误,

类属性 {

public function __get($name)
{
    //return (isset($this->$name)) ? $this->$name : null;

    try {
        if (!isset($this->$name)) {
          throw new Exception("Property $name is not defined");
        }
        return $this->$name;
      }
      catch (Exception $e) {

        return $e->getMessage(); 
      }
}

}

但结果不是我想要的,因为它throw是错误消息("Property $name is not defined")而不是nullfor $property->bla

我怎样才能让它$property->bla->bla,$property->bla->bla->bla等抛出错误消息?

4

2 回答 2

2

你不能。

__get()函数的范围内,你只知道$property->blah. 你不知道它之后会发生什么,因为那是语言的功能。

请注意对 的评估顺序$foo = $property->blah->blah2->blah3

  1. $temp1 = $property->blah;
  2. $temp1 = $temp1->blah2;
  3. $foo = $temp1->blah3;

当然,$temp1这是虚构的,但这本质上是执行该语句时发生的情况。您的__get()呼叫只知道该列表中的第一个呼叫,仅此而已。您可以做的是处理调用方的错误,使用property_exists()或检查null

$temp = $property->blah;
if( $temp === null || !property_exists( $temp, 'blah2')) {
    throw new Exception("Bad things!");
}

请注意,如果返回的对象也依赖于,property_exists()则会失败,但这在 OP 中并不清楚。$temp__get()

于 2012-11-14T16:57:27.470 回答
1

实际上,当您调用$property->foo->bar并且$property类具有魔术 __get 方法时,您只能验证foo属性并仅为它抛出错误。

但是如果你foo也是同一个类的实例(或具有相同魔法__get方法的类似类),你也可以验证bar属性并抛出下一个错误。

例如:

class magicLeaf {
    protected $data;
    public function __construct($hashTree) {
        $this->data = $hashTree;
    }
    // Notice that we returning another instance of the same class with subtree
    public function __get($k) {
        if (array_key_exists($k, $this->data)) {
             throw new Exception ("Property $name is not defined");
        }
        if (is_array($this->data[$k])) { // lazy convert arrays to magicLeaf classes
            $this->data[$k] = new self($this->data[$k]);
        }
        return $this->data[$k];
    }
 }

现在只是使用它的示例:

$property = new magicLeaf(array(
    'foo' => 'root property',
    'bar' => array(
        'yo' => 'Hi!',
        'baz' => array(
            // dummy
        ),
    ),
));
$property->foo; // should contain 'root property' string
$property->bar->yo; // "Hi!"
$property->bar->baz->wut; // should throw an Exception with "Property wut is not defined"

所以现在你可以看到如何让它几乎像你想要的那样。

现在只需修改一点 your__construct和 magic__get方法并添加新参数以了解我们在每个级别的位置:

...
    private $crumbs;
    public function __construct($hashTree, $crumbs = array()) {
        $this->data = $hashTree;
        $this->crumbs = $crumbs;
    }
    public function __get($k) {
        if (array_key_exists($k, $this->data)) {
             $crumbs = join('->', $this->crumbs);
             throw new Exception ("Property {$crumbs}->{$name} is not defined");
        }
        if (is_array($this->data[$k])) { // lazy convert arrays to magicLeaf classes
            $this->data[$k] = new self($this->data[$k], $this->crumbs + array($k));
        }
        return $this->data[$k];
    }
...

我认为它应该像你想要的那样工作。

于 2013-03-27T23:49:19.170 回答