【问题标题】:why use __set() & __get() method rather than declare a property as public为什么使用 __set() 和 __get() 方法而不是将属性声明为 public
【发布时间】:2015-01-25 09:24:43
【问题描述】:

我是 php 新手。我知道 __set() 和 __get() 创建受保护的属性,但它的行为类似于公共属性。并且通过此方法创建的属性设置为受保护。但唯一的区别是它们可以通过任何方式访问时间从任何地方就像公共属性一样。由于我没有任何 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);

【问题讨论】:

标签: php get set


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-10
      • 2012-04-05
      • 2016-06-22
      • 2011-07-23
      • 1970-01-01
      相关资源
      最近更新 更多