views:

43

answers:

3

First of all: A quite similar problem has been posted and somehow solved already, but is still not answering my specific problem. More about this later.

In words: I have a base class which provides some methods to all childs, but doesn't contain any property. My child is inheriting these methods, which should be used to access the child's properties. If the child's property is protected or public, all works fine, but if the child's property is private, it fails without error (just nothing happens).

In code:

class MyBaseClass {
    public function __set($name, $value) {
        if(!property_exists($this, $name))
            throw new Exception("Property '$name' does not exist!");
        $this->$name = $value;
    }
}

class ChildClass extends MyBaseClass {
    public $publicProperty;
    protected $protectedProperty;
    private $privateProperty;
}

$myChild = new ChildClass();
$myChild->publicProperty = 'hello world';    //works of course!
$myChild->protectedProperty = 'hello world'; //works as expected
$myChild->privateProperty = 'hello world';   //doesn't work?

The above mentioned similar problem got the solution to use the magic __set() method to access the private properties, but this I am already doing. If I implement __set() within the child, it works of course, but the idea is, that the child inherits the __set() from it's parent, but obviously it can't access the child's private method.

Is that on purpose? Am I doinf something wrong? or is my approach just crap by design?

Background: My original idea was: The whole dynamic thing about __set() is something I don't like. Usually a private property should never be accessible from outside, so I implemented throwing __set- and __get-methods in my ultimate base class (from which all classes inherit).

Now I want to dynamicially spawn an instance from an XML file and therefore need access to properties. I made the rule, that any XML-instantiatable class needs to implement the magic __set() method and so can be created dynamicially. Instead of implementing it in every Class that might be spawned some day, I decided to make them inherit from a class called like class Spawnable { } which provides the needed __set-method.

+3  A: 

This is the difference between private and protected. Private methods and properties cannot be inherited or reached. You will need to change them to protected instead.

See the manual on visibility

Members declared protected can be accessed only within the class itself and by inherited and parent classes. Members declared as private may only be accessed by the class that defines the member.

Emil Vikström
You are right of course! I somehow 'imagined', that the __set() method is within the child's scope, because it inherited it from the base class. This would mean that the child wants to access it#s own private properties by using the parent's method. But obviously in PHP the child is actually not 'importing' the methods from the parent, but rather just calling them, like `Parent::Method()`. So it gets out of the visibility and can - of course - only access public and protected fields. This is very unsatisfying, though I know now. Many thanks for your help!
Jan
A: 

I guess you could fashion something using Reflection. For example, in your Spawnable class:

public function __set($name, $value)
{
    $reflector = new ReflectionClass(get_class($this));
    $prop = $reflector->getProperty($name);
    $prop->setAccessible(true);
    $prop->setValue($this, $value);
}

Not the prettiest of code, though.

Frode
Oh nice? Wait a sec! Using Refelction I can actually make private propüerties temporarily accessible, inject values and make them inaccessible again? That will solve a lot of my problems.
Jan
...of course it's not the best approach, but usually I keep my privates sealed anyway. I just need it to implement .NET's way of having XML-Configs with objects which can be instanciated at runtime. Very nice feature, which i want in my php framework. Thanks for the hint, I will check the reflection documentation.
Jan
Yes, all sorts of nastiness can be done with reflection. Keep in mind that it's fairly slow, though.
Frode
A: 

After reviewing my concept, I think it's a bad idea, to go with that approach. This is a general issue with PHP's lack of differing between properties and fields. Of course private fields should never be accessible from outside, but only properties, which are defined by the programmer. The absence of auto-properties (and I don't mean these magical methods __set() and __get()) or some conventional rules for property access, makes it difficult to guess, which naming convention has been used by the programmer when implementing setters for private fields in his class.

The better concept here might be, to rely on the existence of well-named setters for each spawnable class, although it might break, if someone contributed code, which is not implementing the expected conventional named setters.

However, many thanks for your thoughts and hints!

Nylle