代码之家  ›  专栏  ›  技术社区  ›  user1032531

限制getter和setter可访问属性

  •  0
  • user1032531  · 技术社区  · 6 年前

    如何使用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");
        }
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Don't Panic    6 年前

    你可以稍微修改一下第二种方法。在中定义可访问的密钥 $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中严格避免公共属性。如果它们无论如何都可以通过magic方法公开访问,我宁愿将它们声明为public,以便更清楚地说明类是如何工作的。