PHP Magic Methods -

Let’s say you’re developing an Object-Oriented PHP application. You’ve heard about PHP’s magic methods and have been curious about them — what are they?  How do I use them? why would I want to? Let’s work together to answer those questions.

Magic methods are a feature of PHP’s object orientation. Magic methods are methods that are called, behind the scenes by PHP, when you use an object in particular ways. They are identifiable by the leading double underscores in method names. There are currently 15 magic methods supported by PHP, far too many for one article. Today I’ll be focusing on 2 of them — __get() and __set().

For your reference, here is list of PHP magic methods (listed alphabetically):

  • __construct()
  • __destruct()
  • __call()
  • __callStatic()
  • __get()
  • __set()
  • __isset()
  • __unset()
  • __sleep()
  • __wakeup()
  • __toString()
  • __invoke()
  • __set_state()
  • __clone()
  • __debugInfo()

Well Known Magic Methods

The most well known magic method in PHP is the constructor, which is called when creating a new object. The name of the method is __construct(). It’s used to perform initialization upon object creation. Another well known PHP magic method is __toString(), which allows you use an object in a string context. These two are well travelled territory. So let’s move on.

Magic is Bad (usually)

As a general rule, magic in code is bad. It usually makes the logic of the code harder to follow.  In this sense, magic is anything where knowledge is assumed to be understood. For example, if there was an equation that multiplied a number by 86400, you might be scratching your head. However a variable like $seconds_in_a_day = 86400 it becomes clear. Systems that use convention over configuration feel like magic to me, which is why I avoid them if possible. Let’s continue!

Get and Set

You’re a good developer, so you know that we should be using encapsulation with a getter and setter for each of our properties. You might ask – If we’re using encapulation, then we shouldn’t need __get or __set, correct? Perhaps, but lets investigate.

The PHP manual tells us the __get() and __set() methods deal with inaccessible properties which are properties “that have not been declared or are not visible in the current scope

__set() is run when writing data to inaccessible properties.

__get() is utilized for reading data from inaccessible properties.

What does this mean? It means any property that is declared public will not trigger these methods. Lets start by creating a small class called Person, and create two public properties called $firstname and $lastname. Then create an instance of Person and try to set and get the $firstname and $lastname property. Your code should look like the following.

class Person
{
public $firstname = '';
public $lastname = '';
}

$me = new Person();
$me->firstname = 'Andrew';
$me->lastname = 'Woods';

echo "firstname={$me->firstname}\n";
echo "lastname={$me->lastname}\n";

This works as you expect. There $firstname and $lastname properties are set, then read and displayed a couple of lines down. Now lets add a protected property called $zipcode and a couple of lines to write and read it.

protected $zipcode = '';

// outside of the class
$me->zipcode = '98109';

echo "zipcode={$me->zipcode}\n";

This new code will cause an error. “PHP Fatal error:  Cannot access protected property Person::$zipcode in …”

Earlier, it was mentioned that  __set() and __get() methods deal with inaccessible methods – which is exactly what zipcode is. Let’s create a __set and __get method in our Person class.

public function __set($name, $value){
echo "using __set: name={$name} value={$value}\n";
}

public function __get($name){
echo "using __get: name={$name} \n";
}

Now we can see the magic methods we added are working, and the error is gone.

Why would you want to these magic methods? Under what conditions might we not know which properties are being used? Or be unable to use the defined getters and setters? I have a couple of ideas.

Possible scenarios:

  • Processing Database results
  • Conversion from other Data Format e.g. json
  • Map one property name to another
  • Graceful in error handling

Let’s review where we’re at with the code.

class Person
{
    public $firstname = '';
    public $lastname = '';
    protected $zipcode = '';

    public function __set($name, $value){
        echo "using __set: name={$name} value={$value}\n";
    }

    public function __get($name){
        echo "using __get: name={$name} \n";
    }
}

$me = new Person();

// Setting Values
$me->firstname = 'Andrew';
$me->lastname = 'Woods';
$me->zipcode = '98109';

// Getting Values
echo "firstname={$me->firstname}\n";
echo "lastname={$me->lastname}\n";
echo "zipcode={$me->zipcode}\n";

Processing Database Results

When you get results from a database, each record can be an array or an object. In either case, you don’t always control the names of the database fields. The mysqli extension does provide a parameter on the fetch_object() method to allow you to specify your own class. Adding __set and __get to your class would provide you some flexibility.

Map one property name to another

What if you wanted to make $zip work to update the $zipcode property. For your Candian colleagues, you could also have $postal_code update the $zipcode property. These kinds of decisions also apply to using __get() when retrieving values. There’s a saying “be conservative in what you output, and be liberal in what you accept”. These magic methods can help you in that effort.

Graceful in error handling

The use of the __get and __set magic methods can be used to make error handling more graceful. You could throw an Exception to let the client programmer determine what to do. Alternatively, you could let the assignment happen, and add an error_log() message. This kind of decision depends upon your project.

Conclusion

Now you know about PHP’s magic methods – what they are, and how to use them. Consider how you might make use of them in your next project.

Seeking Public Speaking Opportunities

I’ve changed a lot over the years. One thing that hasn’t changed though, is that I like to help people, and share what I know. The opportunity doesn’t always present itself though. As much as writing blog posts provides that opportunity, writing can be hard to convey what I want to share with people. It’s part of why I don’t write nearly as much as I should. There’s far my knowledge in my head than I sometimes have the patience to write down. I find it easier to convey information verbally, but writing affords me the ability to plan. I think teaching people via public speaking would be a good outlet for me, since I’d get the best of both worlds.

Until this past year, I was afraid of public speaking. Since then, I’ve changed. Now I’m seeking speaking opportunities and want to share what I know. I’ve pitched the last few WordCamps and conferences that I’ve wanted to attend. They weren’t accepted, but that’s ok. Last week, I had the opportunity to speak at the Seattle PHP meetup. The talk I gave was teaching the Fundamentals of Object Oriented Programming Using Robots from Popular Culture, or more succinctly Robot OOP. I had been wanting to give it for a while. One of the reasons I’ve been excited at the idea of doing this talk, was because of my unique approach to presenting the ideas of OOP. Learning should be fun. So I really wanted to take this opportunity to prove it. Who wouldn’t want to watch a talk that included Wall-E, The Cylons, and Voltron? I think it worked. It went really well. I received compliments from several people that they enjoyed my talk. I don’t where it’ll be yet, but I’m looking forward to my next speaking opportunity.

Seattle Web Developer of WordPress and PHP websites