简体   繁体   中英

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

I am new to php.I know __set() and __get() create protected property but it behaves like a public property.And properties created by this method are set to PROTECTED.But only difference is that they can be accessed any time from anywhere just like public properties.As i don't have any practical working experience on php,I would like to know why not create a public property instead of taking the trouble of using __get() and __set() ??Also __set() property creates property during runtime. Does it create a problem while tracking all the properties of an object ??

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

It's all to do with encapsulating the data in a class so that the outer world cannot directly modify the values of this data. If you're repeatedly setting the values of a variable from outside class you might want to think about if the variable you're changing should actually be in its current class. You can also have more control over the variable's accessibility. For example, just providing a get() method and preventing yourself from setting a value when you shouldn't really be doing it. Having a method to set the value of something also provides a very handy place for validation rather than checking values outside the class where you may forget from time to time. Also protected properties are different from public properties as they can't be accessed anywhere, just in the variable's own class or classes inherited from the class the variable is in.

There's very little reason to use __get, __set (or __call for that matter) in a way where the actual data structure is fixed (eg you have a fixed set of members and only access them through those methods.

The advantage of these methods lies in situations where you don't actually have a fixed structure. While these situations should usually be avoided there are some situations where this may become handy.

For instance I have a model class for a very lightweight ORM which doesn't require code generation and still features a public interface similar to more complex ActiveRecord style frameworks (i use __call in this and extract the field name from the called method, but __get/__set would work as well).

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

This allows me to rapidly create a model class where at any point I can decide to write a custom setter method. eg if I wanted to store that password as a salted hash I could do something like this:

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;
    }
}

The advantage being that I don't have to write getter/setter methods for every field but at any point can. Very handy in rapid prototyping.

Similar techniques can be used for example if you have some data in array from which you want to modify with object syntax. Using __get/__set allows you to avoid having to go through the array whenever you leave object context back to array context.

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

In the end overloading in PHP is a tool for a pretty specific task (creating dynamic interfaces). If you don't need it, you don't use it. And when you use it, you should be aware that it has its downsides. After all once you overload you're in charge of validation that normally the interpreter could do for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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