PHP 各种范围内的魔术方法

PHP magic methods in various scopes

我一直在阅读 PHP magic methods 并试图更好地理解它们。 PHP 手册中指出:

The overloading methods are invoked when interacting with properties or methods that have not been declared or are not visible in the current scope.

我已经阅读了 "not visible" 的含义:

The visibility of a property, a method or (as of PHP 7.1.0) a constant can be defined by prefixing the declaration with the keywords public, protected or private.

所以请考虑下面的 class:

<?php
    class MyClass{
        private $x = 1;
        protected $y = 2;
        public $z = 3;

        public __construct(){}

        function __get($name){
           switch(true){
             case ($name == 'x'):
                 return 4;
             case ($name == 'y'):
                 return 5;
             case ($name == 'z'):
                 return 6;
             case ($name == 'w'):
                 return 0;
           }
        }

        function sum(){
            return $this->x + $this->y + $this->z;
        }

    }
?>

考虑到上面关于 "visible" 和 "scope" 的片段,__get 魔法方法将在什么情况下被调用,什么时候不会被调用?

如果我实例化一个新对象:$myclass = new MyClass(),会 $myclass->sum() return 615 还是其他什么?

如果我调用 $myclass->x$myclass->y$myclass->z,结果会是 453,因为xy 在技术上不是 "visible"?

我假设调用 $myclass->w 将 return 0 无论范围如何,因为它从未被定义为 class 的 属性 开始是吗?

So considering the snippets above regarding "visible" and "scope", under what context will the __get magic method get invoked and when will it not?

当访问对象上不存在的 属性 时,或从不存在的范围访问 属性 时,将调用 __get 方法无障碍。例如,$obj->foo 将始终触发 __get,而当从 class.

外部调用时,$obj->x 将触发 __get

If I instantiate a new object: $myclass = new MyClass(), will $myclass->sum() return 6 or 15 or something else?

它将 return 6 (1 + 2 + 3)。 $this->x->y->z 都可以从 class 中访问,因此这里不会触发 __get 方法。

What if I call the $myclass->x, $myclass->y, $myclass->z, will the results be 4, 5 and 3 since x and y are technically not "visible"?

正确。

I assume calling $myclass->w will return 0 regardless of scope since it wasn't ever defined as a property of the class to begin with, is that right?

正确,只要您没有明确地为 $myclass->w 赋值。

class MyClass {
    private $x = 1;
    protected $y = 2;
    public $z = 3;
    // ...
}

MyClass class 的代码中,所有实例属性($x$y$z)都是可见的。 sum() 函数会看到它们,并且在使用它们时无需调用 __get().

如果代码试图访问同一 class 的另一个对象的 protectedprivate 属性,也会发生这种情况。例如:

class MyClass {
    private $x = 1;
    protected $y = 2;
    public $z = 3;

    public function copyFrom(MyClass $that) {
        $this->x = $that->x;
        $this->y = $that->y;
        $this->z = $that->z;
    }
}

$a = new MyClass();
$b = new MyClass();
$b->copyFrom($a);

copyFrom() 方法可以访问 $that 对象的所有属性(因为它与 $this 具有相同的 class)和 __get()未被调用。

但是对于这段代码:

$a = new MyClass();
echo($a->x + $a->y + $a->z);

魔术方法 __get() 被调用两次,分别是 $a->x$a->y 因为这些属性在 MyClass class 之外的代码中不可见.


一般来说,如果class没有定义__get()方法,当访问一个不可见的属性进行读取时,解释器会触发致命错误:

PHP Fatal error: Uncaught Error: Cannot access private property MyClass::$x

__get() 的存在抑制了错误。而是调用 __get() 并使用 returns 的值。如果 __get() 没有 return 值(不管为什么),将使用 NULL 代替(这是函数的标准 PHP 行为)。