我正在创建一个BaseModel类,并希望使用魔术方法__set和__get,而不是为每个属性定义setter和getter。
我目前正在使用变量变量,因为我无法通过Google搜索找到另一种方式。变量变量被认为是不好的做法还是我一无所知?
abstract class BaseModel implements \ArrayAccess {
/**
* Don't allow these member variables to be written by __set
*
* @var array
*/
protected $noSet = array();
/**
* Don't allow these member variables to be retrieved by __get
*
* @var array
*/
protected $noGet = array();
public function offsetExists( $offset )
{
return property_exists($this, $offset);
}
public function offsetGet( $offset )
{
return $this->__get($offset);
}
public function offsetSet( $offset , $value )
{
return $this->__set($offset, $value);
}
public function offsetUnset( $offset )
{
unset($this->$offset);
}
public function __get($member)
{
if( $member == 'noSet' || $member == 'noGet')
{
throw new \InvalidArgumentException ("Tried to access a forbidden property", 1);
}
if( ! property_exists($this, $member))
{
throw new \InvalidArgumentException ("Tried to access a non-existent property", 1);
}
if( in_array($member, $this->noGet))
{
throw new \InvalidArgumentException ("Tried to access a forbidden property", 1);
}
return $this->$member;
}
public function __set($member, $value)
{
if( $member == 'noSet' || $member == 'noGet')
{
throw new \DomainException ("Tried write to a non-writable property.", 1);
}
if( ! property_exists($this, $member))
{
throw new \InvalidArgumentException ("Tried to access a non-existent property", 1);
}
if( in_array($member, $this->noSet))
{
throw new \DomainException ("Tried write to a non-writable property.", 1);
}
return $this->$member = $value;
}
答案 0 :(得分:0)
首先,您似乎认为protected
关键字无法使用魔术方法设置/获取属性。不是这种情况。这只是让你无法从类的范围之外直接访问/修改这些属性(即你不能做$object->foo = 'bar'
之类的事情)
其次,你似乎对魔术方法有误解。他们实际上做的是在用户试图直接访问/修改属性时强制执行行为。所以在我的例子中,如果用户试图这样做:
$object->foo = 'bar';
这实际上是调用__set()
方法,相当于:
$object->__set('foo', 'bar');
因此,使用get / set魔术方法的典型类实现可能如下所示:
class some_class {
protected $foo;
protected $foo2;
public $pub;
public function __construct() {
// maybe do something here
}
public function __get($prop) {
if(!property_exists($this, $prop) {
throw new Exception('Tried to get unknown property ' . $prop);
} else {
return $this->{$prop};
}
}
public function __set($prop, $value) {
if(!property_exists($this, $prop) {
throw new Exception('Tried to set unknown property ' . $prop);
} else {
$this->{$prop} = $value;
return true; // or whatever you want to return
}
}
}
用法如下:
$object = new some_class();
$object->foo = 'bar'; // sets 'bar'
echo $object->foo; // echo 'bar;
var_dump($object->foo2); // null
$object->pub = 'something'; // does not call __set() as this property is available from global scope
echo $object->pub; // echo 'something' does not call __get() as this property is available from global scope
$object->no_prop; // throws Exception from __get() as property does not exist
尝试从班级中实际调用__get()
或__set()
似乎是一种奇怪的用法。
查看有关对象重载的PHP文档以获取更多信息:
http://www.php.net/manual/en/language.oop5.overloading.php#object.get
答案 1 :(得分:-1)
变量确实是可行的方法。