使用魔术方法 __get 和 __set 的 PHP 可见性

标签 php oop get visibility

我最近参加了一次面试,我提供的代码具有获取和设置变量的神奇函数。我的代码如下:

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

在采访中,那个人问我变量的可见性,我设置了私有(private)变量,但现在可以使用魔术函数访问这些变量。本质上我在这一点上没有通过面试,所以我想了解更多。我正在学习 PHP Master 的教程,发现了一个不同的 __get,我试图破解它,但它似乎有效,但方式很奇怪。

我调用 __get('test') 来获取我的变量 _test 但如果它被设置为私有(private),它会再次调用自身并告诉我它无法访问 __测试。我真的不明白为什么它会再次调用自己。

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;

}

谁能给我一些关于在类中使用可见性时正确使用 __get 和 __set 的指示,以及为什么这个函数会再次调用自身。

我已经阅读了这里的其他帖子,但我仍在为这个概念而苦苦挣扎。

最佳答案

我刚碰到这个问题,有一点可能值得澄清:

I do not really understand why it calls itself again.

代码不会再次调用自身,而是尝试执行自定义的 getter(如果已定义的话)。让我分解方法执行:

public function __get($name)
{

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

$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));

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

return (method_exists($this, $accessor) && is_callable(array($this, $accessor))) ?
    $this->$accessor() : $this->$field;

最后一部分有点隐晦,因为一行中发生了很多事情:

  • method_exists($this, $accessor)。检查接收者 ($this) 是否具有名称为 $accessor 的方法(在我们的示例中为 getEmail)。
  • is_callable(array($this, $accessor))。检查 setter/getter can be called .
  • 如果两个条件都满足,则调用自定义 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;

}
}

然后运行:

$example = new AccessorsExample();
echo $example->test1 . "\n";
echo $example->test2 . "\n";

你应该看到:

One
Calling the getter
Two

HTH

关于使用魔术方法 __get 和 __set 的 PHP 可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9803434/

相关文章:

php - MySQL 结果数组到 session 变量

java - JPanels,使用监听器改变大小

c# - 如何在 C# 中覆盖属性的 setter 方法?

php - 调整选择方法以接受多个参数

php - 是否可以在执行 jquery GET 请求时将值发送到 php 文件

jQuery $.get : search the data response to get some attribute value

PHP/AJAX 插入 mysql 数据库时出现问题

php - Rackspace 云文件 : Image Upload to rackspace cloud files using PHP

php - 禁用Laravel 8中的Auth Register路由?

oop - 具有状态和行为的对象