PHP __get and __set magic methods
__get
, __set
, __call
and __callStatic
are invoked when the method or property is inaccessible. Your $bar
is public and therefor not inaccessible.
See the section on Property Overloading in the manual:
__set()
is run when writing data to inaccessible properties.__get()
is utilized for reading data from inaccessible properties.
The magic methods are not substitutes for getters and setters. They just allow you to handle method calls or property access that would otherwise result in an error. As such, there are much more related to error handling. Also note that they are considerably slower than using proper getter and setter or direct method calls.
Best practice: PHP Magic Methods __set and __get
I have been exactly in your case in the past. And I went for magic methods.
This was a mistake, the last part of your question says it all :
- this is slower (than getters/setters)
- there is no auto-completion (and this is a major problem actually), and type management by the IDE for refactoring and code-browsing (under Zend Studio/PhpStorm this can be handled with the
@property
phpdoc annotation but that requires to maintain them: quite a pain) - the documentation (phpdoc) doesn't match how your code is supposed to be used, and looking at your class doesn't bring much answers as well. This is confusing.
- added after edit: having getters for properties is more consistent with "real" methods where
getXXX()
is not only returning a private property but doing real logic. You have the same naming. For example you have$user->getName()
(returns private property) and$user->getToken($key)
(computed). The day your getter gets more than a getter and needs to do some logic, everything is still consistent.
Finally, and this is the biggest problem IMO : this is magic. And magic is very very bad, because you have to know how the magic works to use it properly. That's a problem I've met in a team: everybody has to understand the magic, not just you.
Getters and setters are a pain to write (I hate them) but they are worth it.
Magic Methods php, __call __get and __set?
Anytime an inaccessible method is invoked __call
will be called.
Anytime you try to read a property __get
will be called, whether it's echo $obj->prop;
or $var = $obj->prop;
And lastly, anytime you try to write to a property the __set
magic method will be called.
About PHP Magic Methods __get and __set on inheritance
Your code should be resulting in a fatal error because you're trying to access a private property. Even before that, you should receive a syntax error because you haven't properly declared your functions. Hence, you're "resulting" var dump can never occur.
Edit:
You've edited your question. The reason it doesn't work is because bar
is private to Foo
(SuperFoo
cannot access it). Make it protected
instead.
Practical applications of PHP magic methods - __get, __set, and __call
__call()
I've seen it used to implement behaviors, as in add extra functions to a class through a pluginable interface.
Pseudo-code like so:
$method = function($self) {};
$events->register('object.method', $method);
$entity->method(); // $method($this);
It also makes it easier to write mostly similar functions, such as in ORMs. e.g.:
$entity->setName('foo'); // set column name to 'foo'
__get()/__set()
I've mostly seen it used to wrap access to private variables.
ORMs are the best example that comes to mind:
$entity->name = 'foo'; // set column name to 'foo'
Php __get and __set magic methods - why do we need those here?
You (usually) never call __set
or __get
directly. $foo->bar
will call $foo->__get('bar')
automatically if bar
is not visible and __get
exists.
In the tutorial you've linked to, the getter and setter get set up to automatically call the appropriate individual get/set functions. So $foo->comment = 'bar'
will indirectly call $foo->setComment('bar')
. This isn't necessary... it's only a convenience.
In other cases, __get
can be useful to create what looks like a read-only variable.
Possible to use magic methods __get and __set for both array and nonarray class member variables?
Simple, define __get()
like so:
public function &__get($name)
{
return $this->$name;
}
// ...
$fun = new example();
$fun->a = 'yay';
$fun->b['coolio'] = 'yay2';
var_dump($fun);
Output:
object(example)#1 (2) {
["a":protected]=>
string(3) "yay"
["b":protected]=>
array(1) {
["coolio"]=>
string(4) "yay2"
}
}
Do take necessary care when you're dealing with references, it's easy to mess up and introduce hard to track bugs.
Can the __set and __get methods behave differently inside and outside of a class?
The magic __get and __set methods are only called when accessing a property which has not been explicitly declared. The reason your code is working as shown is that $session_namespace is just another undeclared property, so setting it calls __set, regardless of where that call is made.
What you need to do, therefore, is add a line declaring that property to your class definition such as private $session_namespace
(it doesn't matter if it's public, protected, or private, but the general rule is to restrict things first, and relax the restrictions only when needed).
PHP will see the declared property, set it as a normal variable, and not call __set, while any other name will still call the magic methods. As a bonus, a private or protected variable will be considered to not exist when called from a public context, so it should even be possible to set $_SESSION['testing']['session_namespace'] if you for some reason wanted to.
Magic methods (__get, __set) not working in extended class?
This would work:
public function __get($theName)
{
if(property_exists($this, $theName)) {
$reflection = new ReflectionProperty($this, $theName);
$reflection->setAccessible($theName);
return $reflection->getValue($this);
}
}
IMO, you shouldn't use __get
and __set
as a replacement for getters and setters. Since they are triggered when trying to access a non-accessible property, they are much more related to error-handling. And they are also much slower than a regular getter or setter.
Related Topics
Multiple Files Upload in Codeigniter
Is Micro-Optimization Worth the Time
How to Loop Through a MySQL Result Set
Prevent Direct Access to File Called by Ajax Function
Is MySQL_Real_Escape_String() Broken
How to Give PHP Write Access to a Directory
What Does the "[^][]" Regex Mean
Resize Animated Gif File Without Destroying Animation
PHP String Concatenation, Performance
Incorrect Integer (2147483647) Is Inserted into MySQL
"Smtp Error: Could Not Authenticate" in PHPmailer
MySQL: Select Random Entry, But Weight Towards Certain Entries
Formatting Datetime Object, Respecting Locale::Getdefault()