theintz
theintz

Reputation: 1987

strange php oop behavior, can someone explain?

In a nutshell: a class inherits a function from its parent. This function then gets called on the child, but appears to still have the scope of the parent class. Is this expected behavior?

Consider the following code example:

<?php
class OLTest {
    private $var1 = 10;

    public function getVar1() {
        if (isset($this->var1)) {
            return $this->var1;
        } else {
            return 'undefined';
        }
    }

    public function getVar2() {
        if (isset($this->var2)) {
            return $this->var2;
        } else {
            return 'undefined';
        }
    }
}

class OLTest2 extends OLTest {
    private $var1 = 11;
    private $var2 = 20;
}

$oltest = new OLTest();
$oltest2 = new OLTest2();

echo "calling parent->getVar1\n";
echo $oltest->getVar1() . "\n";

echo "calling parent->getVar2\n";
echo $oltest->getVar2() . "\n";

echo "calling child->getVar1\n";
echo $oltest2->getVar1() . "\n";

echo "calling child->getVar2\n";
echo $oltest2->getVar2() . "\n";
?>

To my understanding, the output should be:

calling parent->getVar1
10
calling parent->getVar2
undefined
calling child->getVar1
11
calling child->getVar2
20

The actual output on my machine is:

calling parent->getVar1
10
calling parent->getVar2
undefined
calling child->getVar1
10
calling child->getVar2
undefined

To add to the confusion, a print_r($this) within either of the functions, will show that the scope is really set to the subclass, yet it's impossible to access the variable.

Can someone clear this up for me?

EDIT: I am using PHP in version 5.3.3-1ubuntu9.5.

Upvotes: 2

Views: 169

Answers (6)

Phill Pafford
Phill Pafford

Reputation: 85308

It's the scope of your private variables, try using protected

class OLTest {
    protected $var1 = 10;

    public function getVar1() {
        return isset($this->var1) ? $this->var1:'undefined';
    }

    public function getVar2() {
        return isset($this->var2) ? $this->var2:'undefined';
    }
}

class OLTest2 extends OLTest {
    protected $var1 = 11;
    protected $var2 = 20;
}

$oltest  = new OLTest();
$oltest2 = new OLTest2();

echo "calling parent->getVar1\n".$oltest->getVar1()."\n";
echo "calling parent->getVar2\n".$oltest->getVar2()."\n";
echo "calling child->getVar1\n".$oltest2->getVar1()."\n";
echo "calling child->getVar2\n".$oltest2->getVar2()."\n";

Results:

calling parent->getVar1
10
calling parent->getVar2
undefined
calling child->getVar1
11
calling child->getVar2
20

Upvotes: 0

Slava
Slava

Reputation: 2050

Yes, it is because your properties are private. The methods you are calling still belong to parent class as you haven't redefined them. To enable parent methods accessing child's properties you must make them protected in both parent and child classes:

class OLTest {
    protected $var1 = 10;

    public function getVar1() {
        if (isset($this->var1)) {
            return $this->var1;
        } else {
            return 'undefined';
        }
    }

    public function getVar2() {
        if (isset($this->var2)) {
            return $this->var2;
        } else {
            return 'undefined';
        }
    }
}

class OLTest2 extends OLTest {
    protected $var1 = 11;
    protected $var2 = 20;
}

If you keep it private in parent class it won't allow child class to override that property, so the function belonging to parent class will be accessing its own private property. And if you make it private in child class it won't allow parent methods to access it.

If you still want to keep them private you'll have to copy-paste code of your methods into child class (yes, return parent::getVar1() won't work either).

Upvotes: 2

Kru
Kru

Reputation: 4235

No, the output should definetly be 10, undefined, 10, undefined. The reason is that the variables that are private are visible only to the class defining them (not super or subclasses).

So, when child is called, its methods are defined in the parent object and when they resolve var1 or var2 they check in the scope definied for OLTest. var2 is not accessible too because the declared var2 is only visible inside OLTest2.

To get your output, your should declare these variables protected or public.

Upvotes: 4

Dan Simon
Dan Simon

Reputation: 13117

Because you have declared your vars private, they are totally hidden from each other. Thus the $var1 in the parent is actually a different variable from the $var1 in the child

When you call getVar1 on the parent, it uses the $var1 it sees, the one from the parent with the value 10. Similarly the parent cannot see the child's $var2, so to it the property is undefined.

When you call getVar1 and getVar2 on the child, the methods themselves are inherited from the parent class and behave exactly as they would if they were called from an object of the type OLTest

Upvotes: 1

J. Bruni
J. Bruni

Reputation: 20492

It seems to be related to the private scope.

Try changing to protected or public anc check the results.

Upvotes: 2

Michael J.V.
Michael J.V.

Reputation: 5609

You cannot "inject" private $var2 into the parent class, which is what you were trying to do. So yes, that is normal behavior.

Upvotes: 1

Related Questions