Page 1 of 2

__get() and __set()

Posted: Sat Sep 02, 2006 4:37 am
by onion2k
I've been looking at __get() and __set(). Are they really as pointless as they appear? It's good practise to define all your object's properties, and as these only work for undefined properties .. why bother with them? They seem to encourage use of undefined, and therefore public, variables.

Posted: Sat Sep 02, 2006 5:03 am
by volka
onion2k wrote:They seem to encourage use of undefined, and therefore public, variables.
Why?

Posted: Sat Sep 02, 2006 5:20 am
by onion2k
volka wrote:
onion2k wrote:They seem to encourage use of undefined, and therefore public, variables.
Why?
Because they only work on undefined properties. If you've defined the property (eg public $var; or private $var; etc) then you have to write your own accessors. Using __set() will create the property, but you have no control over the scope .. it's always public. And that's not a good thing.

Posted: Sat Sep 02, 2006 5:47 am
by volka
What's the relevant difference between "your own accessors" and those implemented in __get/set()?
And if you have some kind of composition/aggregation it can make things easier.

Posted: Sat Sep 02, 2006 6:03 am
by onion2k
volka wrote:What's the relevant difference between "your own accessors" and those implemented in __get/set()?
I define a class "user".

I decide I want 5 variables called firstName, lastName, userName, password, and status.

I decide I want firstName, and lastName to be public.

I decide I want userName, and password to be protected,

I decide I want status to be private.

My code:

Code: Select all

class user {
  public $firstName, $lastName;
  protected $userName, $password;
  private $status;
}
__get() and __set() no longer work with these variables because they've been defined. So I have to write my own access functions.

If I don't define the variables then I can use __get() and __set() to read and write them, but then all of them will be public. Which is bad.

Posted: Sat Sep 02, 2006 6:42 am
by volka
Then you may have a class where __set/get is not appropriate, ok. Not everything is applicable or best practice everywhere.

If I don't define the variables then I can use __get() and __set() to read and write them
Only if you implement get/set this way. But you're not forced to do so.

Posted: Sat Sep 02, 2006 7:41 am
by feyd
I've demonstrated various behaviours of the __get and __set overloads in several T&D threads. Dig them out, they may be interesting.

Posted: Sat Sep 02, 2006 8:29 am
by Christopher
onion2k wrote:
volka wrote:
onion2k wrote:They seem to encourage use of undefined, and therefore public, variables.
Why?
Because they only work on undefined properties. If you've defined the property (eg public $var; or private $var; etc) then you have to write your own accessors. Using __set() will create the property, but you have no control over the scope .. it's always public. And that's not a good thing.
The fact that these magic methods were implemented as error handlers is unfortunate. I don't like it either. But that's just the way it is in PHP currently and __get() and __set() give some great functionality at the cost of not having real properties.

Posted: Sat Sep 02, 2006 8:48 am
by Jenk

Code: Select all

class Foo
{
    private $bar = 'foo';

    public __get ($name)
    {
        return 'bar!';
    }
}

$foo = new Foo;

echo $foo->bar;
outputs:

Code: Select all

bar!
same for protected.

Posted: Sat Sep 02, 2006 2:32 pm
by Todd_Z

Code: Select all

class foo {
  private $array;
  public function __construct ( ) {
   $this->array = new Array();
  }
  public function __get ( $var ) {
    if ( ! array_key_exists($var) )
      throw new Exception( 'Variable No Exist!' );
    return $this->array[ $var ];
  }
  public function __set ( $var, $val ) {
    $this->array[ $var ] = $val;
  }
}
I have a database abstraction layer that takes full advantage of this sort of capability. With magic methods you can keep track of which vars have been altered, etc, without changes the syntax for accessing the values.

Posted: Sat Sep 02, 2006 11:54 pm
by timvw
Do we actually want properties? Here are a couple of observations from the C# world:

- Properties were 'invented' to allow RAD designers.. In essence, properties are methods, with usually relatively simple logic...

- By default every property is show in the designer. If you want to hide or limit the manipulation of properties that can be done by the browser you have to add attributes such as Browsable and ReadOnly to the property signature...

Thus it makes me wonder: Why do we need properties? To me it seems we could do equally well with functions only... And then add an attribute to the methods we want to appear in the designer.... (Compare it to access rights: only give what is needed.. Don't give root and then take away what seems unneeded ;))

Notice that this is probably off-topic since it's a different discussion than the one on having __get/__set magic :)

Posted: Sun Sep 03, 2006 7:43 am
by Chris Corbyn
They are really for dynamic situations with variable property names. Say, data from a DB that you may store in an array but __get() and __set() make the data available through properties. They are just accessors, and you're not really making the data public, in fact, you can make a one-way read-or-write situation using them by implementing __get() but not __set() or so forth.

I agree that 9 times out of 10 you should be using real get() and set() methods to access that data but they do come in very useful for manipulating data in complex ways.

You can also use them as nice little factories:

$document->body->setTile('foo');

They are going to come in very useful in mocking requests to properties too. I think Marcus is already working on that now.

Posted: Sun Sep 03, 2006 4:29 pm
by Christopher
timvw wrote:Do we actually want properties? Here are a couple of observations from the C# world:
I find this question a little startling because properties are really an essential part of objects. Remember that objects are Data + Methods. But it is the data that gives each object a large part if its identity and maintains it state. I think as programmers we tend to focus on the behavior part that it is data, not us, that is important. ;)

Posted: Sun Sep 03, 2006 6:44 pm
by volka
I think 'properties' is meant as

Code: Select all

public int primaryGroup {
	get {
		if (!valid())
			fetchUserData();
		return userdata.primaryGroup;
	}
	
	set {
		userdata.primaryGroup = value;
		dirty();
	}
}

[...]
i = obj.primaryGroup;
it's masking the get/set method calls as a simple member access.

Posted: Mon Sep 04, 2006 1:12 am
by timvw
d11wtq wrote:They are really for dynamic situations with variable property names.
In my opinion they aren't very suitable for object oriented programming... Since the interface doesn't expose which properties are available (you can only find out by 'trying' if $object->property doesn't throw an exception...)
d11wtq wrote: You can also use them as nice little factories:
$document->body->setTile('foo');
If i'm not mistaken PHP has operator chaining since 5.0 too, so it's not very different than:
$document->getBody()->setTile('foo');
d11wtq wrote: They are going to come in very useful in mocking requests to properties too. I think Marcus is already working on that now.
I think that for a decent solution of that problem you would need a language that supports introspection/reflection..