繁体   English   中英

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

[英]why use __set() & __get() method rather than declare a property as public

我是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);

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

几乎没有理由以固定实际数据结构的方式使用__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中的重载是一个用于完成特定任务(创建动态接口)的工具。 如果不需要它,就不要使用它。 当您使用它时,您应该意识到它有缺点。 毕竟,一旦您超载,您就将负责通常由解释器为您完成的验证。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM