__get神奇的方法 - 如何抛出和捕获属性重载的错误



我定义当利用__get魔术方法访问不存在的属性时会发生什么。

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

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

但是当我知道$property->bla不存在时,我想抛出并抓住错误$property->bla->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 $property->bla

如何使其针对$property->bla->bla$property->bla->bla->bla等抛出错误消息?

实际上

,当您调用$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"

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

现在只需稍微修改一下您的__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];
    }
...

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

你不能。

__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!");
}

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

相关内容

最新更新