限制 getter 和 setter 可访问属性

Restrict getter and setter accessible properties

如何使用 PHP 的魔法 __get()__set() 方法并限制支持哪些属性?

我经常看到 PHP 的魔术方法用于重载以下两种方式,但都没有这样做。

我知道我可以硬编码一些逻辑,但这样做并不能使 类 非常可扩展。

$obj1=new Entity1(new Foo, new Bar);
$obj1->propAccessible1='propAccessible1';           //Valid
var_dump($obj1->propAccessible1);                   //Valid
$obj1->privateObject1='privateObject1';             //Should not be allowed
var_dump($obj1->privateObject1);                    //Should not be allowed
$obj1->unsupportedProperty='unsupportedProperty';   //Correctly is not allowed
var_dump($obj1->unsupportedProperty);               //Correctly is not allowed

$obj2=new Entity2(new Foo, new Bar);
$obj2->propAccessible1='propAccessible1';           //Valid
var_dump($obj2->propAccessible1);                   //Valid
$obj2->privateObject1='privateObject1';             //Should not be allowed
var_dump($obj2->privateObject1);                    //Should not be allowed (will be if first set using setter)
$obj2->unsupportedProperty='unsupportedProperty';   //Should not be allowed
var_dump($obj2->unsupportedProperty);               //Should not be allowed

class Foo{}
class Bar{}

class Entity1
{
    private $privateObject1, $privateObject2;
    private $propAccessible1, $propAccessible2;

    public function __construct($injectedObject1, $injectedObject2) {
        $this->privateObject1=$injectedObject1;
        $this->privateObject2=$injectedObject2;
    }

    public function __get($property) {
        if (property_exists($this, $property)) return $this->$property;
        else throw new \Exception("Property '$property' does not exist");
    }

    public function __set($property, $value) {
        if (!property_exists($this, $property)) throw new \Exception("Property '$property' is not allowed");
        $this->$property = $value;
        return $this;
    }
}

class Entity2
{
    private $privateObject1, $privateObject2;
    private $data=[];

    public function __construct($injectedObject1, $injectedObject2) {
        $this->privateObject1=$injectedObject1;
        $this->privateObject2=$injectedObject2;
    }

    public function __set($property, $value) {
        $this->data[$property] = $value;
    }

    public function __get($property) {
        if (array_key_exists($property, $this->data)) {
            return $this->data[$property];
        }
        else throw new \Exception("Property '$property' does not exist");
    }
}

您可以稍微修改一下第二种方法。在 $data 中定义您的可访问密钥,并检查这些密钥是否存在于 __set() 中,就像您在 __get().

中所做的那样
class Entity2
{
    private $privateObject1, $privateObject2;
    private $data = [
        'accessible1' => null,
        'accessible2' => null
    ];

    public function __construct($injectedObject1, $injectedObject2)
    {
        $this->privateObject1 = $injectedObject1;
        $this->privateObject2 = $injectedObject2;
    }

    public function __set($property, $value)
    {
        if (array_key_exists($property, $this->data)) {
            $this->data[$property] = $value;
        } else throw new \Exception("Property '$property' does not exist");
    }

    public function __get($property)
    {
        if (array_key_exists($property, $this->data)) {
            return $this->data[$property];
        } else throw new \Exception("Property '$property' does not exist");
    }
}

不过,我并不是真的相信在 PHP 中严格避免使用 public 属性。如果它们无论如何都 public 只能通过魔术方法访问,我宁愿将它们声明为 public 以更清楚地说明 class 是如何工作的。