有没有更好的方法来定义__get而不使用变量变量或数组用于所有成员变量?

时间:2013-12-13 19:20:21

标签: php

我正在创建一个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;
}

2 个答案:

答案 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)

变量确实是可行的方法。