PHP __set and __get Magic methods
Object oriented programming principles encourage encapsulation, i.e. containing all the functionality inside a class. Usually this means member variables should be private or protected, one of the common ways to do this is with various set and get methods. In the case of a user class it may have setName, getName, setAge, getAge and so on. This can be time consuming to set up, change and maintain. The magic methods __set and __get provide a quick way to implement generic set and get methods.
-
<?php
-
-
class Foo{
-
-
private $name;
-
private $age;
-
-
public function setName($name){
-
$this->name = $name;
-
}
-
-
public function getName(){
-
return $this->name;
-
}
-
-
public function setAge($age){
-
$this->age = $age;
-
}
-
-
public function getAge(){
-
return $this->age;
-
}
-
-
}
-
-
$foo = new Foo();
-
$foo->setName("Dougal");
-
$foo->setAge(10);
-
-
-
class Bar{
-
-
private $name;
-
private $age;
-
-
public function __set($var, $val){
-
$this->$var = $val;
-
}
-
-
public function __get($var){
-
return $this->$var;
-
}
-
-
}
-
$bar = new Bar();
-
$bar->name = "Dougal";
-
$bar->age = 10;
-
The script outputs the same thing twice, just showing different methods;
“Dougal is 10 years old
Dougal is 10 years old”
In the above example class Foo uses set and get methods while class Bar uses the magic methods. To summarise __set and __get, basically if you are trying to access a property of an object (and it has a __get method) the name of the property you are requesting is passed into the get method and it can handle it how it wants. __set works the same but it is only called when you attempt to assign a value to a member variable. The only difference being __set takes two paramemters, the variable its setting and the value.
You might wonder what the point in __set and __get is, well one good example is when a class has dynamic properties.
-
<?php
-
-
class DynamicFoo{
-
-
-
public function __construct(){
-
-
}
-
-
public function __set($var, $val){
-
$this->vars[$var] = $val;
-
}
-
-
public function __get($var){
-
return $this->vars[$var];
-
} else {
-
throw new Exception("Property ‘$var’ does not exist");
-
}
-
}
-
-
}
-
-
$dynamicFoo = new DynamicFoo();
-
-
$dynamicFoo->hello = “world”; // sets the properly
-
-
?>
You can now also do some slightly more interesting things too… take this example…
-
<?php
-
class DynamicUser{
-
-
private $firstname = "";
-
private $surname = "";
-
-
public function __set($var, $val){
-
$this->$var = $val;
-
}
-
-
public function __get($var){
-
-
-
return $this-$var;
-
-
-
return $this->$var();
-
-
} else {
-
-
throw new Exception("Property ‘$var’ does not exist");
-
}
-
}
-
-
-
public function fullname(){
-
return $this->firstname . " " . $this->surname;
-
}
-
-
}
-
-
$x = new DynamicUser();
-
-
$x->firstname = "dougal";
-
$x->surname = "matthews";
I wouldn’t really recommend this way, its more an example of what can be done rather than anything else. Basically the above method “guesses” that if the property doesn’t exist you meant to call a method by the same name and returns the result of that method instead.
The nice thing about this is it can be completely transparent to the user.
Next I’ll be looking at a __call, a magic method for when you call functions!

August 6th, 2008 at 6:06 pm
So if you implement __set & __get inside a class, then does that mean all your private variables are now exposed? Can you limit it to only operating on certain variables?
Ta.
August 6th, 2008 at 6:15 pm
Yes, this would mean that they are all then made public. You can of course manage it inside the __get/__set method. Various ways to do this, a switch statement would be one.
However, the real puprose for me with these methods is to allow for more dynamic coding. Thus aiming towards are more dynamic OO style rather than say Java style oo.
August 20th, 2008 at 9:10 pm
To clarify what Dougal said, *if you implement __set() and __get() as done in this blog post*, then all your variables essentially become public.
Obviously, then, implementing __set() and __get() as done in this blog post isn’t very useful (just declare all your vars public instead). It was done simply because it was very simple and illustrated the way the functions worked well.
In *real* code, using __set and __get can be very interesting. That very last example that Dougal provided - where __get() first checks if the var exists, and if it doesn’t calls a function named after the var, is in fact very useful. It’s exactly the pattern used in languages like Ruby and Lisp (using CLOS), and even C#. There’s an excellent script here to implement it automatically in PHP: http://railsforphp.com/2007/12/21/accessing-attributes-in-php-objects/
That linked script sets up your __get and __set functions (you have to inherit from the provided class) so that you can register a set of variable names that should be “magic”. Whenever someone tries to access a “magic” variable (say, as $myObj->var), your __get function will first check if there is a function named getVar(). If so, it calls it. If not, it then checks if there is a *protected* variable named $_var. If so, it returns it. If not, it then checks if you’ve set up a function named _get() (notice the single _). If so, it delegates to it. If none of this works, it throws an error.
This lets you do really cool stuff, and I use it all the time. Frex, I put together a simple class that, among other things, stores a list of links to things. I originally exposed $link as a simple public variable, but realized later that *sometimes* I’d want to return the stored $link value, but other times I’d want to return another link entirely. I was faced with potentially refactoring all of my code that asked for $obj->link into $obj->getLink(). Instead, I popped this in, changed my public $link to a protected $_link, added a getLink() method, and it all worked transparently. My code still just asked for $obj->link, but it was *really* calling $obj->getLink() and everything worked wonderfully.
August 20th, 2008 at 9:24 pm
Thanks for taking the time to expand on that for me. Some very interesting points.
I’ll be checking out that link!
I do feel slightly uneasy about the magic methods sometimes. For example, having so much functionality made ‘invisible’ could lead to some very hard debugging!
September 11th, 2008 at 8:26 am
Instead of creating a new property every time, can’t you just store them in an array.
add property:
private $vars = array();
public function __set($key, $val)
{
$this->vars[$key] = $val;
}
public function __get($key)
{
return $this[$key];
}
September 11th, 2008 at 2:00 pm
Indeed, you can indeed. However, either way is valid. So I guess thats just down to preference
February 11th, 2009 at 12:47 am
Umair said in post #5:
add property:
…..
What is that? I think I’ve seen this in other people’s code but haven’t been able to find out the meaning of it. Looks like a label of some sort, but PHP doesn’t have it, does it? And I think I’ve seen it in Javascript code.
February 11th, 2009 at 1:28 am
Roman,
I believe Umair meant add the property $vars to the class. A property is just a class variable.
Perhaps you are talking about something else? If you can show me the JavaScript code I may be able to understand what you mean.
February 11th, 2009 at 6:44 am
You are probably right, Dougal. But here’s a little of a Javascript code from Jquery library:
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {
// Make sure that a selection was provided
selector = selector || document;
What’s the init: for? This must be a part of JS syntax I haven’t gotten to yet.
February 11th, 2009 at 9:12 am
Oh, it is initialization of an associative array, isn’t it?
February 11th, 2009 at 9:22 am
init is actually something jQuery has added to JavaScript, its their own implementation of a constructor.
The above would look something like this in PHP…
class jQuery{
public function __constructor(selector, context ){
// Make sure that a selection was provided
selector = selector || document;
}
}
February 11th, 2009 at 9:24 am
Sorry, indentations don’t work in my comments but you can see it more easily here http://pbin.eu/4/
February 12th, 2009 at 2:44 pm
class div{
$nom;
$denom;
function do_it()
{
echo $nom/$denom;
}
}
how would you use a set method to validate $denom from entering “0″
February 12th, 2009 at 2:54 pm
I don’t think I would, I would probably check it in the do_it function.
However, if you really wanted to… Something like this could work http://pbin.eu/5/ but its not really that nice…
March 24th, 2009 at 8:06 pm
“The script outputs the same thing twice,[...]”
Of course it does! It’s the same echo statement. =p
If you look at your first bit of code, the second “echo” statement is using “$foo” again, instead of “$bar”. Looks like it was a copy/paste but forgot to update the proper variable. It might be a little confusing for the less experienced. =)
Thanks for the post. I need the quick refresh!
March 24th, 2009 at 8:24 pm
Fozzy, nice catch! That was a bit silly of me…
May 12th, 2009 at 10:29 pm
Why would declaring a private member and defining __get and __set methods within a class effectively make the private member public?
May 26th, 2009 at 11:46 am
PHP code to parse XML using PHP Magic Methods
I do need dynimically access object parameters from xml parser.But donot have any ideas onhow to dynamically access object parameters.How to implement magic code on it.
Here is my static code:
foreach ($x->data->DIPENDRA20090320[0]->ENTRY as $valuei) {
echo “ID: “.$valuei->_text->ID;
echo “Name: “.$valuei->_text->NAME;
echo “Address: “$car->_text->ADDRESS;
}
Let me know whenever you will get this message.I would really appreciate
your help.
Regards,
Padma