如何使用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");
}
}
答案 0 :(得分:1)
您可以稍微修改第二种方法。在$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中的公共属性。如果他们无论如何都会通过魔术方法公开访问,我宁愿将它们声明为公开,以便更清楚地说明该课程是如何工作的。