PHP _Get and _Set Magic Methods

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



Leave a reply



Submit