tags:

views:

21

answers:

1

I'm using the __get() and __set() magic methods in order to intercept external calls to some private attributes without the need of writing a setter and a getter for each attribute. So far so good:

<?

class Foo{
    private $id;
    private $info = array();
    private $other;

    public function __set($name, $value){
        switch($name){
            case 'id':
            case 'info':
                return $this->$name = $value;
                break;
            default:
                throw new Exception('Attribute "' . $name . '" cannot be changed from outside the class');
        }
    }

    public function __get($name){
        switch($name){
            case 'id':
            case 'info':
                return $this->$name;
                break;
            default:
                throw new Exception('Attribute "' . $name . '" cannot be read from outside the class');
        }
    }
}

$MyFoo = new Foo;

$MyFoo->id = 33;
$MyFoo->info = array (
  'item_id' => '20',
  'issue' => '53',
);
try{
    $MyFoo->other = 44;
}catch(Exception $e){
    echo 'Exception raised as expected: ' . $e->getMessage();
}

?>

Now I need to test whether certain attribute (an array) remains empty or not. I realized that empty($MyFoo->info) was always false so I looked up in the manual and I found __isset():

__isset() is triggered by calling isset() or empty() on inaccessible properties.

However, it's not clear to me how I should implement __isset() in my code. I guess it's supposed to return true or false but... can I distinguish between being called via empty() or via isset()?

+1  A: 

You need to do it this way:

public function __isset($name) {
    return isset($this->$name);
}

In this case isset($MyFoo->info) and empty($MyFoo->info) will work as expected:

// isset($MyFoo->info) --> true
// empty($MyFoo->info) --> false
$MyFoo->info = array(1, 2, 3);

// isset($MyFoo->info) --> true
// empty($MyFoo->info) --> true
$MyFoo->info = array();

// isset($MyFoo->info) --> false
// empty($MyFoo->info) --> true
$MyFoo->info = null;
Alexander Konstantinov
You are right. It seems that empty() triggers __isset() but it doesn't use its return value directly.
Álvaro G. Vicario
empty() first calls __isset(), then, if it returns true, __get() to check existing attribute's value for emptiness.
Alexander Konstantinov