为什么要使用__set()& __get()方法而不是将属性声明为public

时间:2015-01-25 09:24:44

标签: php get set

我是php的新手。我知道__set()和__get()创建了受保护的属性,但它的行为类似于公共属性。此方法创建的属性设置为PROTECTED。但唯一的区别是它们可以被访问时间就像公共财产一样。由于我没有任何关于PHP的实际工作经验,我想知道 为什么不创建一个公共财产而不是麻烦使用__get()和__set() ?? __ set()属性也会在运行时创建属性。 在跟踪对象的所有属性时是否会产生问题 ...

class foo {
   protected $another='lol';  //protected property


    public function __get($name) {


        return $this->$name;
    }

    public function __set($name, $value) {


        $this->$name = $value;
    }
}

class bar extends foo{     // inherits from foo

    public function __get($name){   //__get() method for bar class
        return $this->$name;       //
    }
}

$foo = new foo();

$foo->bar = 'test';

echo $foo->another;  //echos protected property from parent class

echo '</br>';

$bar=new bar();

echo $bar->another;   //  echos inherited private property from parent class

var_dump($foo);

2 个答案:

答案 0 :(得分:1)

所有这些都与将数据封装在类中有关,因此外部世界无法直接修改此数据的值。如果您反复设置来自外部类的变量值,您可能需要考虑您正在更改的变量是否应该实际位于其当前类中。您还可以更好地控制变量的可访问性。例如,只提供一个get()方法,并防止自己在不应该这样做时设置一个值。设置某个值的方法也为验证提供了一个非常方便的位置,而不是检查您可能不时忘记的类外的值。受保护的属性也不同于公共属性,因为它们无法在任何地方访问,只能在变量自己的类或从变量所在的类继承的类中访问。

答案 1 :(得分:1)

没有理由以实际数据结构固定的方式使用__get,__ set(或__call)(例如,你有一组固定的成员,只能通过这些方法访问它们。

这些方法的优点在于您实际上没有固定结构的情况。虽然通常应该避免这些情况,但在某些情况下这可能会变得很方便。

例如,我有一个非常轻量级ORM的模型类,它不需要代码生成,并且仍然具有类似于更复杂的ActiveRecord样式框架的公共接口(我在此使用__call并从被调用的方法中提取字段名称) ,但是__get / __ set也可以。)

class User extends AbstractModel {
    protected static $FIELD_LIST = ['id', 'username', 'password'];
}

$foo = new MyModel();
$foo->setId(123);
$foo->setUsername('Foo');
$foo->setPassword('secret');
$foo->setNonExistantField('World!'); // will throw an exception

这允许我快速创建一个模型类,在任何时候我都可以决定编写一个自定义的setter方法。例如如果我想将该密码存储为盐渍哈希,我可以这样做:

class User extends AbstractModel {
    protected static $FIELD_LIST = ['id', 'username', 'password'];

    public function setPassword($password) {
        $salt = magic_salt_function();
        $hash = crypt($password, '$2a$08$' . $salt);
        $this->data['password'] = $hash;
    }
}

优点是我不必为每个字段编写getter / setter方法,但在任何时候都可以。在快速原型制作中非常方便。

例如,如果您希望使用对象语法修改数组中的某些数据,则可以使用类似的技术。使用__get / __ set可以避免在将对象上下文返回到数组上下文时必须遍历数组。

class Foo {
    protected $data;

    public function __construct(array $data) {
        $this->data = $data;
    }

    public function __get($key) {
        if(!isset($this->data[$key])) {
            throw new Exception("Unknown member $key");
        }

        return $this->data[$key];
    }

    public function __set($key, $value) {
        if(!isset($this->data[$key])) {
            throw new Exception("Unknown member $key");
        }

        $this->data[$key] = $value;
    }

    public function getData() {
        return $this->data;
    }
}

$data = [
    'bar' => true,
    'braz' => false
];
$foo = new Foo($data);
$foo->bar = false;
$foo->braz = true;
$foo->nope = true; // will throw an exception

最后,PHP中的重载是一个非常特定的任务工具(创建动态接口)。如果您不需要它,则不要使用它。当你使用它时,你应该意识到它有它的缺点。毕竟,一旦你超负荷,你就负责通常由口译员为你做的验证。