PHP __set() Magic Method Conundrum
I am completely baffled by this one and hope one of my techie friends can help.
I’m using a PHP class with magic methods to set and get the properties of that class. The idea is to use private properties in the class so that the PHP magic methods can take over and determine whether to update a WordPress user meta entry, blog entry, or standard option based on which proper of the class is being retrieved or stored.
Here is a sample psuedo-class based on a real-world implementation. It is simplified so there may be syntax issues.
Class MyThing { private $account_stats; private $status; /** * Special interface for private properties. * * @param $property * * @return null */ function __get( $property ) { if ( ! property_exists( $this , $property ) ) { return null; } if ( !isset( $this->$property ) ) { global $blog_id, $user_id; switch ( strtolower($property) ) { case 'account_stats': $this->$property = get_blog_option( $blog_id , 'account_status' ); break; case 'status': $meta = get_user_meta( $user_id ); break; } } } /** * Set our private properties. * @param $property * @param $value * * @return null */ function __set( $property , $value ) { if ( ! property_exists( $this , $property ) ) { return null; } global $blog_id, $user_id; switch ( strtolower($property) ) { case 'account_stats': $this->$property = $value; update_blog_option( $blog_id , 'account_status' , $value ); break; case 'status': $this->$property = $value; update_user_meta( $user_id , $property , $value ); break; } } function set_account( $state ) { $this->account_stats = $state; $this->status = $state; } }
The problem in the real-world code is that this call:
$thing = new MyThing(); $this->set_account( 'active' );
Does NOT call the __set() magic method for the account_stats property.
It DOES call the __set() magic method for the status property.
According to PHP any attempt to set an “inaccessible property” will fire the __set() magic method. OK, so a private property is available to the methods of the class which, in my mind, means BOTH the account_stats AND the status properties are accessible and would NOT call the __set() magic method. Yet the magic method IS called for the $this->status = $state line.
The patch it to call the setter directly in set_account:
function set_account( $state ) { $this->__set( 'account_stats' , $state ); $this->__set( 'status' , $state ); }
Does anyone know a PHP guru out there that might be able to explain this one? Why is the private property status handled differently than the private property account_status? The order of the statements in the set_account() method do not make a difference. Using $this->status always fires the __set() magic method but $this->account_stats does not.