13

I'm trying to make functions like empty() and isset() work with data returned by methods.

What I have so far:

abstract class FooBase{

  public function __isset($name){
    $getter = 'get'.ucfirst($name);
    if(method_exists($this, $getter))
      return isset($this->$getter()); // not working :(
      // Fatal error: Can't use method return value in write context 
  }

  public function __get($name){
    $getter = 'get'.ucfirst($name);
    if(method_exists($this, $getter))
      return $this->$getter();
  }

  public function __set($name, $value){
    $setter = 'set'.ucfirst($name);
    if(method_exists($this, $setter))
      return $this->$setter($value);
  }

  public function __call($name, $arguments){
    $caller = 'call'.ucfirst($name);
    if(method_exists($this, $caller)) return $this->$caller($arguments);   
  }

}

the usage:

class Foo extends FooBase{
  private $my_stuff;

  public function getStuff(){
    return $this->my_stuff;
  }

  public function setStuff($stuff){
    $this->my_stuff = $stuff;
  }
}


$foo = new Foo();

if(empty($foo->stuff)) echo "empty() works! \n"; else "empty() doesn't work:( \n";
$foo->stuff = 'something';
if(empty($foo->stuff)) echo "empty() doesn't work:( \n"; else "empty() works! \n";

http://codepad.org/QuPNLYXP

How can I make it so empty/isset return true/false if:

  • my_stuff above is not set, or has a empty or zero value in case of empty()
  • the method doesn't exist (not sure if neeed, because I think you get a fatal error anyway)

?

Alex
  • 66,732
  • 177
  • 439
  • 641
  • `isset(..)` only works on a value, not on a function that returns a value. See the notes section: http://php.net/manual/en/function.isset.php – Kevin Jun 05 '11 at 11:28
  • Don't use magic __get and __set if you have normal getters and setters. Accessors exists exactly to avoid using public properties (because it's violation of encapsulation). – OZ_ Jun 05 '11 at 11:34
  • http://stackoverflow.com/questions/21227585/what-is-the-difference-between-isset-and-isset – Lal krishnan S L Feb 25 '14 at 08:56

3 Answers3

10
public function __isset($name){
    $getter = 'get'.ucfirst($name);
    return method_exists($this, $getter) && !is_null($this->$getter());
}

This check whether or not $getter() exists (if it does not exist, it's assumed that the property also does not exist) and returns a non-null value. So NULL will cause it to return false, as you would expect after reading the php manual for isset().

Arjan
  • 9,784
  • 1
  • 31
  • 41
  • 1
    +1 Short and clean :) Only thing that should be added is that `$this->$getter()!==null` is faster than `!is_null($this->$getter())` :) – Tadeck Jun 05 '11 at 12:10
  • 3
    It's faster, but the difference is very small. Whether you use `!== null` or `!is_null()` is a matter of taste, not speed optimization. – Arjan Jun 05 '11 at 12:23
  • I agree again :) The difference is small and it is more a question of taste. +1 again – Tadeck Jun 05 '11 at 12:51
  • http://stackoverflow.com/questions/21227585/what-is-the-difference-between-isset-and-isset will help you – Lal krishnan S L Feb 25 '14 at 08:57
3

A bit more option not to depend on getter

public function __isset($name)
{
    $getter = 'get' . ucfirst($name);
    if (method_exists($this, $getter)) {
        return !is_null($this->$getter());
    } else {
        return isset($this->$name);
    }
}
  • If you like, you can omit the else for readability. (since the if is returning early, you could safely do that) – Bert H Apr 25 '18 at 06:55
1

Your code returns error because of these lines:

if(method_exists($this, $getter))
return isset($this->$getter());

You can just replace it with:

if (!method_exists($this), $getter) {
    return false; // method does not exist, assume no property
}
$getter_result = $this->$getter();
return isset($getter_result);

and it will return false if the getter is not defined or it returns NULL. I propose you should better think of the way you determine some property is set or not.

The above code is also assuming that you are creating getters for all of your properties, thus when there is no getter, the property is assumed as not set.

Also, why are you using getters? They seem to be some overkill here.

Tadeck
  • 132,510
  • 28
  • 152
  • 198
  • If a property is `NULL` I would say it is not set, so `isset()` correctly returns false. And using getters and setters may seem overkill, but they do allow to refactor parts of the application without breaking other things. – Arjan Jun 05 '11 at 11:39
  • @Arjan Correct, `NULL` makes `isset()` return `false`. Also now I see that `isset($foo->stuff)` has some reason. To be short: because `$foo->stuff` is really something based on `$foo->my_stuff`, but processed by getter. – Tadeck Jun 05 '11 at 11:49
  • well I followed your advice and ended up using getter/setter only for two variables which really need them, and for the rest I created normal get/setVariable() functions (I was using them for almost all private varibles) – Alex Jun 05 '11 at 12:37
  • @Alex By saying "getter" or "setter", I meant function getting variable or function setting variable. So now you actually use getters & setters for all of your variables, if I understand you correctly. But ok, if you need getters & setters, just use them - I am happy you walked through your code and redesigned it in a way you think is better now :) – Tadeck Jun 05 '11 at 12:50
  • yes, I still use getter/setter for all variables, but only for two of them I'm using the __set/__get magic methods :) This is because those two variables are objects and I think it's more natural to call them like `$foo->objectvariable->somemethod` instead of $foo->getObjectvariable()->somemethod` – Alex Jun 05 '11 at 12:56
  • @Alex Ok, now I get your point. As far as your approach is concerned - I think you know what you are doing (and - more importantly - you know what you want to achieve) :) – Tadeck Jun 05 '11 at 13:02