使用Magic方法的PHP可见性__get&__ set

Cha*_*ant 5 php oop visibility get

我最近去了一个面试,我提供的代码有魔术函数来获取和设置变量.我的代码如下:

public function __get($name){
    try { 
        return $this->$name;
    } catch (Exception $e) { 
        throw new Exception('Trying to get a variable "'.$name.'" that does not exist.'); 
    }
}
Run Code Online (Sandbox Code Playgroud)

在采访中,这个人告诉我关于变量的可见性,我设置了私有变量,但现在可以通过使用魔术函数来访问它们.基本上我在这一点上没有通过采访,所以我想了解更多.我正在按照PHP Master的教程发现一个不同的__get,我试图打破它,但它似乎工作,但以一种奇怪的方式.

我打电话__get('test')来获取我的变量_test但是如果它被设置为私有它再次调用自己并告诉我它无法访问__test.我真的不明白为什么它再次自称.

public function __get($name)
{
    $field = '_' . strtolower($name);

    if (!property_exists($this, $field)){
        throw new \InvalidArgumentException(
            "Getting the field '$field' is not valid for this entity"
        );
    }

    $accessor = 'get' . ucfirst(strtolower($name));
    return (method_exists($this, $accessor) && is_callable(array($this, $accessor))) ?
        $this->$accessor() : $this->$field;

}
Run Code Online (Sandbox Code Playgroud)

任何人都可以给我一些关于在类中使用可见性时正确使用__get和__set以及为什么这个函数会再次调用自身的指针.

我已经阅读了其他帖子,但我仍在努力解决这个问题.

And*_*ier 5

我刚刚提出这个问题,有一件事可能值得澄清:

我真的不明白为什么它再次自称.

代码不是再次调用自己,而是尝试执行自定义的getter(如果有一个定义的).让我分解方法执行:

public function __get($name)
{
Run Code Online (Sandbox Code Playgroud)

正如在其他答案和此处已经解释的那样,当您尝试访问未在调用范围中声明或不可见的属性时,将调用__get()魔术方法.

$field = '_' . strtolower($name);

if (!property_exists($this, $field)){
    throw new \InvalidArgumentException(
        "Getting the field '$field' is not valid for this entity"
    );
}
Run Code Online (Sandbox Code Playgroud)

这里只检查类定义中是否存在预先附加下划线的属性.如果没有,则抛出异常.

$accessor = 'get' . ucfirst(strtolower($name));
Run Code Online (Sandbox Code Playgroud)

这里它创建了要调用的getter的名称(如果存在).因此,如果您尝试访问一个名为的属性,email并且有一个名为变量的私有成员_email,$accessor则现在将保存该'getEmail'字符串.

return (method_exists($this, $accessor) && is_callable(array($this, $accessor))) ?
    $this->$accessor() : $this->$field;
Run Code Online (Sandbox Code Playgroud)

最后一部分有点神秘,因为很多事情都在一行中发生:

  • method_exists($this, $accessor).检查receiver($this)是否有一个带$accessor名字的方法(在我们的例子中getEmail).
  • is_callable(array($this, $accessor)).检查是否可以调用 getter .
  • 如果满足两个条件,则调用自定义getter并返回其返回值($this->$accessor()).如果不是,则返回属性内容($this->$field).

作为示例,请考虑此类定义:

class AccessorsExample
{
private $_test1 = "One";
private $_test2 = "Two";

public function getTest2()
{
echo "Calling the getter\n";
return $this->_test2;
}

public function __get($name)
{
    $field = '_' . strtolower($name);

    if (!property_exists($this, $field)){
        throw new \InvalidArgumentException(
            "Getting the field '$field' is not valid for this entity"
        );
    }

    $accessor = 'get' . ucfirst(strtolower($name));
    return (method_exists($this, $accessor) && is_callable(array($this, $accessor))) ?
        $this->$accessor() : $this->$field;

}
}
Run Code Online (Sandbox Code Playgroud)

然后运行:

$example = new AccessorsExample();
echo $example->test1 . "\n";
echo $example->test2 . "\n";
Run Code Online (Sandbox Code Playgroud)

你应该看到:

One
Calling the getter
Two
Run Code Online (Sandbox Code Playgroud)

HTH