An introduction to magic methods
PHP 5 introduced a number of powerful upgrades to assist object-oriented programmers. The one we’re going to look at next is called magic methods. And as you can guess from the name, they’re pretty amazing.
First off, let me explain what makes a method “magic”. A magic method adds some additional functionality to your objects, and the way it works is by providing an interface through which the PHP engine can interact with them. {show website} As of this video, there are 14 magic methods, and I definitely want to encourage you to at least be familiar with all of them. The php manual at php.net has an excellent treatment of them, but right now, I’m just going to show you the 4 methods that I think you’ll probably get the most use out of.
Now, just so you recognize them, all magic methods identify themselves by having two underscore characters in front of their names. As a commonsense guide, you shouldn’t create them unless you specifically want the magic functionality. Some of these methods can be accessed directly like ordinary methods, while others can’t – if you want to know which are which, the best way to find out is to test. And since any magic methods added in the future will also begin with two underscore characters, it is strongly discouraged for you to begin any of your regular method names that way.
So, the first method I want to show you is called __construct. Like most magic methods, it should be obvious what it does just from its name. In this case, the __construct method gets called as soon as you create a new instance of your class. Whichever arguments you send in your call to the ‘new’ statement also get sent to the __construct method.
This function is called a constructor, and unlike the other magic methods, this functionality isn’t new to PHP 5. However, back before PHP 5, constructors were simply methods defined with the same names as the classes they were defined in. And, to preserve backwards-compatibility, this convention, while deprecated, does still work. If you have both a __construct method, and an old-style constructor, the __construct method will be the only one called during a ‘new’ statement.
The next 3 methods provide brand new functionality that PHP didn’t have before. The common theme here is that they automatically get invoked when your scripts attempt to access properties or methods on your objects that either aren’t defined, or aren’t declared as public.
The first method of these methods is called __get.
When you try to retrieve the value of a property that isn’t public, or doesn’t exist, before triggering a notice, PHP checks to see whether your object has one of these __get methods. If it does, then PHP will invoke it and pass in the name of the property requested by your script as the only argument. Here’s a simple example of a __get method:
{show example code}
Now, in this case, my class doesn’t define any public properties, but it does define a private property called _options, which is an array. So, whenever a property is requested, it checks to see if the _options array has a value set on the same key as the name of the property the script was trying to access. And if there isn’t one set, it just returns false.
The counterpart to the __get method is the __set method, and from the name, you can probably guess that it gets invoked when a script tries to set a property that isn’t public. This method takes 2 arguments. The first is the name of the property to be set, and the second is the value that the script tried to assign that property.
{show example}
In this case, the __set method on my class is extremely simple. It just sets a value on the _options array based on the key and value passed to it.
The last method I’m going to show you is __call. And this one gets invoked whenever a script attempts to access a method that hasn’t been defined or at least hasn’t been declared as public. It accepts 2 arguments – the name of the method requested, and the arguments that the calling script tried to pass to it. The second argument, in this case, is an array.
Now, my class doesn’t define any non-magic methods, but it does have a private property called _helper. _helper is an instance of the Helper class, and that class does define public methods. Well, it defines one anyway.
{show code sample}
So, what I decided to do in my __call method
{show code sample}
is to check to see whether or not the _helper object has a method with the same name as the one that the calling script tried to access, and if it does, it will call that method with the same arguments that were used when the script tried to access it.
Now, if you know your design patterns, you’ll recognize that this a handy technique in case you want to use the Bridge pattern. And actually, I also want to call your attention to the nifty PHP function here ‘call_user_func_array’. In these videos, I make no effort to try and cover all the useful built-in functions PHP comes loaded with (there’s just too many), but this is a pretty cool one. When I call it this way like you see here, it actually acts exactly as though I had called this method here with these arguments, even though they’re variables. That means there’s no performance penalty the way you’d expect if you tried to mimic this exact same functionality using an eval statement. So if you aren’t already familiar with it, I recommend learning about this function and all the different ways it can be invoked. Look it up in the PHP manual when you have a chance.
Back to the topic at hand though, now that I’ve introduced you to these four methods, let’s take a look at some sample code to see them in action.
{show sample code}
Here you see I’m going to create a new instance of my Magical class. Then, I’m going to set a property named ‘two’ with an array, but of course, since my class doesn’t define a property called ‘two’ it’ll have to invoke the ‘__set’ magic method. Next I’m going to retrieve that property, and use var_export to display it on the screen, which means PHP will also have to invoke my __get magic method.
{switch to output}
And there, sure enough, you see the message “I was constructed” coming out of the constructor, and there below it is the exported array. So we know the first 3 methods worked.
{switch to code}
Lastly, I’m going to place a call to a method named ‘doSomething’ which doesn’t actually have a definition in the Magical class, but does have a definition on the Helper class, and you’ll see the output from that.
{switch to output}
And that right there is the correct output based on the arguments I passed.
Now, the line ‘Good-bye’ at the end of the script probably looks a little strange. But it’s there for a good reason. The class ‘Magical’ actually defines all 14 magic methods, and just like there’s one that gets invoked when an object is created, there’s one that gets invoked when an object gets destroyed. In this case, all it does is print out that message ‘Good-bye’. If you’re interested, I invite you to check out the Magical class in the files included with this lesson. There you’ll see at least 10 other methods I didn’t talk about, and if you want to learn even more, just search the PHP manual for “magic methods”.
{show website}
I should mention before I wrap up, that __call has a static analog called __callStatic. It gets invoked when you try to call a static method on a class that hasn’t been declared, or else isn’t declared public. And also, at the time I’m recording this, a change request has been approved by the PHP engineers to incorporate a __getStatic and __setStatic pair of methods as well. Depending on how old these videos are, those methods might be available to you today. I’d use them in some of my scripts right now if I could. As it is, there’s no way to avoid a fatal error if you try to access an undeclared static property.
January 21 2010 11:13 pm | PHP tutorial scripts