__get magic method - 如何为属性重载抛出并捕获错误?

时间:2012-11-14 16:46:25

标签: php try-catch magic-methods

我定义了利用__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")而不是null的{​​{1}}。

如何让它为$property->bla$property->bla->bla抛出错误消息 ,等等?

2 个答案:

答案 0 :(得分:2)

你不能。

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

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

  1. $temp1 = $property->blah;
  2. $temp1 = $temp1->blah2;
  3. $foo = $temp1->blah3;
  4. 当然,$temp1是虚构的,但这基本上就是在执行该语句时发生的事情。您的__get()电话只知道该列表中的第一个电话,仅此而已。您可以做的是使用property_exists()或{0}}检查主叫方面的错误:

    null

    请注意,如果$temp = $property->blah; if( $temp === null || !property_exists( $temp, 'blah2')) { throw new Exception("Bad things!"); } 中返回的对象也依赖property_exists()$temp将失败,但OP中并不清楚。

答案 1 :(得分:1)

实际上,当您调用$property->foo->bar$property类具有magic __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"

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

现在只需修改一下你的__construct和魔术__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];
    }
...

我认为它应该像您想要的那样。