0
class A {
    protected $a = 'aaa';
}

class B extends A {
    protected $a = 'bbb';
    public function __construct(){
       echo parent::$a; // Fatal error: Access to undeclared static property: A::$a in main.php on line 11
    }
}

$b = new B();

I want to access $a variable from class A in constructor of class B. Be aware that $a variable is overwritten in class B. How can I access parent::$a?

4
  • 1
    Why are you redeclaring $a? I cannot see any reason why you would when you can simply update its value in the subclass like so $this->a = 'bbb'; Commented Apr 2, 2014 at 14:50
  • I have variable which is an array in which I store configuration data. I want to create method which will mix parent and child configuration. To do so I have to know variable name. If all classes would have the same variable name it would be easier and I could extend my classes multiple times. Commented Apr 2, 2014 at 14:58
  • 1
    Thanks for the update, I understand where you are coming from now. I have an alternative suggestion, but I want to clarify a few things. It sounds to me like class A has a default configuration, and class B optionally passes in some config values that can add to and/or replace the default config - would this be a fair assertion? Commented Apr 2, 2014 at 15:08
  • Yes, with an emphasis on replace. Commented Apr 2, 2014 at 15:10

4 Answers 4

1

The only way to do this would be to declare $a as static:

protected static $a = 'aaa';

But that will make the value of parent::$a the same for all instances. If you want separate values, this cannot be done, and you'd be better off renaming the variables, eg one is $a and the other is $b.

Sign up to request clarification or add additional context in comments.

1 Comment

I'm setting this comment as accepted answer because it answers my question in 100%.
1
class A {
    protected $a = 'aaa';
}

class B extends A {
    protected $a = 'bbb';
    public function __construct(){
       echo parent::$a; // Fatal error: ...
    }
}

$b = new B();

How can I access parent::$a?

You cant, parent::$a means you are trying to access a static property from a parent class.

instead of doing this,use the constructor to modify $a

class B extends A {
    public function __construct(){
       // do something with $this->a value here;
    }
}

or you'll always overwrite $a if your redeclare it as a property in B.

Comments

1

I just read your comment so I understand your use case a little better now. If you are adding/merging configurations in inheriting classes I'd suggest an alternative approach, adding some behaviour.

As you confirmed above:

  • class A has a default configuration
  • class B can optionally pass in config values that can update/add to the default config

In this case, something like this could work for you:

class A
{
    protected $config = array(
        'foo' => 'foo',
        'bar' => 'bar',
        'baz' => 'baz',
    );

    public function __construct(array $config = array())
    {
        $this->config = array_merge($this->config, $config);
    }

    public function getConfig()
    {
        return $this->config;
    }
}

class B extends A
{
    // implement
}

$b = new B(array(
    'foo' => 'OVERWRITTEN',
    'new' => 'NEW',
));

print_r($b->getConfig());

Yields:

Array
(
    [foo] => OVERWRITTEN
    [bar] => bar
    [baz] => baz
    [new] => NEW
)

You can also overwrite your default config in the same way when using class A directly. Alternatively, instead of implementing the merge in __construct() you could implement that as a setConfig() method.

Hope this helps :)

EDIT

I just want to add one more thing: if your config is a multidimensional array, you will have to change how you merge arrays. At first glance array_merge_recursive() might seem like the obvious candidate. However:

$old = array(
    'foo' => 'foo',
    'bar' => 'bar',
    'baz' => array(
        'baa' => 'baa',
        'boo' => 'boo',
    ),
);

$new = array(
    'foo' => 'FOO',
    'baz' => array(
        'baa' => 'BAA',
    ),
    'new' => 'new'
);

$merge = array_merge_recursive($old, $new);
print_r($merge);

actually yields:

Array
(
    [foo] => Array
        (
            [0] => foo
            [1] => FOO
        )

    [bar] => bar
    [baz] => Array
        (
            [baa] => Array
                (
                    [0] => baa
                    [1] => BAA
                )

            [boo] => boo
        )

    [new] => new
)

Probably not what you are looking for! Instead use array_replace_recursive():

$merge = array_replace_recursive($old, $new);
print_r($merge);

This yields:

Array
(
    [foo] => FOO
    [bar] => bar
    [baz] => Array
        (
            [baa] => BAA
            [boo] => boo
        )

    [new] => new
)

1 Comment

Yes, this is great! Passing config variable in class constructor will do the trick.
0

@Darragh I made it little different because I didn't want to change my constructors:

abstract class A
{
    protected $a = array('a' => 1, 'b' => 2);

    public function __construct()
    {
        $this->mixA();
    }

    protected function a()
    {
        return array();
    }

    protected function mixA()
    {
        foreach ($this->a() as $key => $val) {
            $this->a[$key] = $val; // $val can be an array too (in my case it is)
        }
    }
}

class B extends A
{
    protected function a()
    {
        return array(
            'b' => 'new value',
            'c' => 'new variable'
        );
    }

    public function dumpA()
    {
        var_dump($this->a);
    }
}

$b = new B();
$b->dumpA();

So now if I want to change my default configs I just overwrite a() method. mixA() method can be expanded as needed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.