views:

59

answers:

3

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];
    }
}

Any help of this would be much appreciated.

Thanks,

Leonard

+2  A: 

Is there anyway to declare a variable from within a class as protected?

It doesn't seem so. You can use Reflection to change the accessibility of properties, but it seems that this can only effectively be used to make things public that were not previously public.

You may wish to consider storing automatically generated properties in an an array with the proper visibility.

(There's also __get and __set, but they might not fit your needs. They'd only get called when a property is missing or inaccessible. Classes that are able to touch protected properties would bypass them.)

Charles
Yes, I agree with your 2nd paragraph... store these _generated_ 'properties' in an associative array. The associative array can then be a protected property of your class. In order to use `__get` or `__set` _I think_ you would need to do it this way.
w3d
I disagree. This defeats the point of member variables. I use associative arrays when the class will store unknown variables (Such as a registry class, or something of the like). But why not use member variables for what they were designed for when you have a limited set of known variables?
ircmaxell
I can only imagine, from the question, that he's doing some sort of wacky inheritance and/or visibility magic. Unless the code posted above is incomplete, I don't see any transformation done to the properties...
Charles
+2  A: 

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]);
    }
}
Mark Baker
Thanks, done this. Works perfectly but kept the call method as got a habit of using $class->getSomething();
Leonard Austin
+3  A: 

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...

ircmaxell
+1 Don't agree with $foo->setBar('baz'); being unnecessarily verbode compared to $foo->bar = 'baz'; because getter and setter methods always allows validation for setting attributes, whereas a non-private attribute can always be set bypassing any validation... but a lot of very useful snippets of information here
Mark Baker
It's just a fallback method for any variables that I might need to add to a class. Generally speaking I always use get and set methods when necessary for protected variables. I completely understand the difficulties with debugging and will only be using this method sparingly to achieve DRY.
Leonard Austin
Well, I do use the `getBar()` syntax from time to time, but I try not to unless it really makes sense. I just don't like the clutter of having 50 methods in a class just for getting/setting the member variables... Most of the time it's simply not necessary (but not always)...
ircmaxell