views:

1838

answers:

9

A similar question discusses __construct, but I left it in my title for people searching who find this one.

Apparently, __get and __set take a parameter that is the variable being gotten or set. However, you have to know the variable name (eg, know that the age of the person is $age instead of $myAge). So I don't see the point if you HAVE to know a variable name, especially if you are working with code that you aren't familiar with (such as a library).

I found some pages that explain __get(), __set(), and __call(), but I still don't get why or when they are useful.

+6  A: 

This page will probably be useful. (Note that what you say is incorrect - __set() takes as a parameter both the name of the variable and the value. __get() just takes the name of the variable).

__get() and __set() are useful in library functions where you want to provide generic access to variables. For example in an ActiveRecord class, you might want people to be able to access database fields as object properties. For example, in Kohana PHP framework you might use:

$user = ORM::factory('user', 1);
$email = $user->email_address;

This is accomplished by using __get() and __set().

Something similar can be accomplished when using __call(), i.e. you can detect when someone is calling getProperty() and setProperty() and handle accordingly.

Phill Sacre
A: 

They're for doing "clever" things.

For example you could use __set() and __get() to talk to a database. Your code would then be: $myObject->foo = "bar"; and this could update a database record behind the scenes. Of course you'd have to be pretty careful with this or your performance could suffer, hence the quotes around "clever" :)

Greg
A: 

Overloading methods is especially useful when working with PHP objects that contain data that should be easily accessable. __get() is called when accessing a non-existent propery, __set() is called when trying to write a non-existent property and __call() is called when a non-existent method is invoked.

For example, imagine having a class managing your config:

class Config
{
    protected $_data = array();

    public function __set($key, $val)
    {
        $this->_data[$key] = $val;
    }

    public function __get($key)
    {
        return $this->_data[$key];
    }

    ...etc

}

This makes it a lot easier to read and write to the object, and gives you the change to use custom functionality when reading or writing to object. Example:

$config = new Config();
$config->foo = 'bar';

echo $config->foo; // returns 'bar'
Aron Rotteveel
I dislike this type of use for these methods. It's syntactic sugar at best, and just serves to slow your application down. I'd rather see a class that implements the SPL ArrayAccess interface or just a generic set of get/set methods. These should be "use when necessary, not when convenient".
Peter Bailey
+2  A: 

__get(), __set(), and __call() are what PHP calls "magic methods" which is a moniker I think that is a bit silly - I think "hook" is a bit more apt. Anyway, I digress...

The purpose of these is to provide execution cases for when datamembers (properties, or methods) that are not defined on the object are accessed, which can be used for all sorts of "clever" thinks like variable hiding, message forwarding, etc.

There is a cost, however - a call that invokes these is around 10x slower than a call to defined datamembers.

Peter Bailey
+1  A: 

Redefining __get and __set can be especially useful in core classes. For example if you didn't want your config to be overwritten accidentally but still wanted to get data from it:

private $config = array('password' => 'pAsSwOrD';
public function __get($name)
{
    return $this->config[$name];
}
Ross
A: 

One good reason to use them would be in terms of a registry system (I think Zend Framework implements this as a Registry or Config class iirc), so you can do things like

$conf = new Config();
$conf->parent->child->grandchild = 'foo';

Each of those properties is an automatically generated Config object, something akin to:

function __get($key) {
    return new Config($key);
}

Obviously if $conf->parent already existed, the __get() method wouldn't be called, so to use this to generate new variables is a nice trick.

Bear in mind this code I've just quoted isn't functionality, I just wrote it quickly for the sake of example.

JamShady
A: 

Probably not the cleanest design in the world but I had a situation where I had a lot of code that was referencing an instance variable in a class, i.e.:

$obj->value = 'blah';
echo $obj->value;

but then later, I wanted to do something special when "value" was set under certain circumstances so I renamed the value variable and implemented __set() and __get() with the changes I needed.

The rest of the code didn't know the difference.

bobwienholt
+1  A: 

Another useful application of magic methods, especially __get and __set and __toString is templates. You can make your code independent from template engine just by writing simple adapter that uses magic methods. In case you want to move to another template engine, just change these methods only.

class View {

    public $templateFile;
    protected $properties = array();

    public function __set($property, $value) {
        $this->properties[$property] = $value;
    }

    public function __get($property) {
        return @$this->properties[$property];
    }

    public function __toString() {
        require_once 'smarty/libs/Smarty.class.php';
        $smarty = new Smarty();
        $smarty->template_dir = 'view';
        $smarty->compile_dir = 'smarty/compile';
        $smarty->config_dir = 'smarty/config';
        $smarty->cache_dir = 'smarty/cache';
        foreach ($this->properties as $property => $value) {
            $smarty->assign($property, $value);
        }
        return $smarty->fetch($this->templateFile);
    }

}

Hidden benefit of this approach is that you can nest View objects one inside another:

$index = new View();
$index->templateFile = 'index.tpl';

$topNav = new View();
$topNav->templateFile = 'topNav.tpl';

$index->topNav = $topNav;

And in index.tpl, the nesting looks like that:

<html>
<head></head>
<body>
    {$topNav}
    Welcome to Foobar Corporation.
</body>
</html>

All nested View objects gets converted to string (HTML to be exact) on the fly, as soon as you echo $index;

Michał Rudnicki
A: 

I think it is bad for design you code. If you know and do a good design then you will not need to use the __set() and __get() within your code. Also reading your code is very important and if you are using studio (e.g. Zend studio), with __set() and __get() you can't see your class properties.

guliy