我最近参加了一次面试,我提供的代码具有获取和设置变量的神奇函数。我的代码如下:
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/