Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaring protected variables in methods

I've had a good look round and can't seem to find an answer to this problem.

Basically I'm using the _call method to dynmically generate get and set methods, however when declaring a variable PHP's default is public. Is there anyway to declare a variable from within a class as protected?

function __call($method, $arguments) {
    $prefix = strtolower(substr($method, 0, 3));
    $property = strtolower(substr($method, 3));

    if (empty($prefix) || empty($property)) {
        return;
    }

    if ($prefix == "get" && isset($this->$property)) {
        return $this->$property;
    }

    if ($prefix == "set") {

        $this->$property = $arguments[0];
    }
}
like image 570
Leonard Austin Avatar asked Dec 12 '22 20:12

Leonard Austin


2 Answers

One option would be to have a protected array, and to set an element in that array from your magic setter.

class MyClass {
    protected $_myProperties = array();

    public function __get($name) {
        if (isset($this->_myProperties[$name])) {
            return $this->_myProperties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value) {
        $this->_myProperties[$name] = $value;
    }

    public function __isset($name) {
        return isset($this->_myProperties[$name]);
    }
}
like image 139
Mark Baker Avatar answered Dec 27 '22 20:12

Mark Baker


First off, I'd HIGHLY suggest not returning if the prefix or property variables are not set. It will make debugging VERY difficult. Instead, replace the return; with throw new BadMethodCallException('Method Does Not Exist: '.$method);

Second, isn't that defeating the point of protected variables? It is allowing reading and writing to all properties without any kind of validation. If you're going to do this, you might as well make them public.

I personally find $foo->bar = 'baz'; to be more readable than $foo->setBar('baz');. Not because it's "easier" to understand, but because the second is unnecessarally verbose.

Personally, I'd suggest doing a __get and __set, and adding validation. The whole point of protecting variables is for trust (so that you can trust the settings). Sure, you could use reflection or sub-classing to change them, but I usually assume that if someone goes that far, they deserve to have any unintended concequnces if they mess up a variable.

And keep in mind that if you are using any kind of magic method, you'll need to add documentation elements if you want your IDE to hint the methods/variables to you...

EDIT:

And don't forget, if you declare __get/__set methods, you can override them in the child classes. So if the child declares new variables, you can handle them there, and then call parent::__get to handle the default variables. So don't go with an array just so that you can have one method for all children. Do the validation for the members you know about, and let your children handle their own validation...

like image 33
ircmaxell Avatar answered Dec 27 '22 22:12

ircmaxell