__get() and __set()

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

User avatar
onion2k
Jedi Mod
Posts: 5263
Joined: Tue Dec 21, 2004 5:03 pm
Location: usrlab.com

__get() and __set()

Post 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.
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post by volka »

onion2k wrote:They seem to encourage use of undefined, and therefore public, variables.
Why?
User avatar
onion2k
Jedi Mod
Posts: 5263
Joined: Tue Dec 21, 2004 5:03 pm
Location: usrlab.com

Post 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.
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post 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.
User avatar
onion2k
Jedi Mod
Posts: 5263
Joined: Tue Dec 21, 2004 5:03 pm
Location: usrlab.com

Post 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.
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post 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.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post 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.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post 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.
(#10850)
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post 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.
User avatar
Todd_Z
Forum Regular
Posts: 708
Joined: Thu Nov 25, 2004 9:53 pm
Location: U Michigan

Post 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.
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post 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 :)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post 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.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post 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. ;)
(#10850)
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post 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.
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post 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..
Post Reply