Search code examples
phpinheritanceaccess-levels

Why do I get an "Access Level must be protected or weaker" after extending a protected class variable and marking it private?


abstract class AbstractController
{
    protected $repository;
}

class GraphController extends AbstractController
{
    private $repository;
}

I get this error:

Fatal error: Access level to GraphController::$repository must be protected or weaker

Why? What's the theory behind this? On some level it feels wrong that I could have a weaker access level to a class property (i.e. public) when I extend a class, because I am in a way exposing a variable that was meant by parent class to be more restricted...


Solution

  • This is a response to the comment above having to do with making member vars more visible... not necessarily a response to the original question.

    Try running this fragment. You'll see there will still be a private var lurking underneath your public var by the same name, and depending on whether you access it through base-class methods or derived-class methods, you'll get different results since they are two distinct instance values.

    class baseclass {
        private $hideme;
        public function getit() { return $this->hideme; }
        public function setit($value) { $this->hideme = $value; }
    }
    
    class derived extends baseclass {
        public $hideme;
    }
    
    function doobee(baseclass $obj) {
        echo $obj->getit() . "\n";
    }
    
    $a = new derived();
    $a->hideme = "direct assign";
    $a->setit("accessor assign");
    
    ?><pre><?php
    echo '$a->getit(); // ' . $a->getit() . "\n";
    echo '$a->hideme; // ' . $a->hideme . "\n";
    echo 'doobee($a); // '; doobee($a);
    
    echo 'print_r($a);' . "\n";
    print_r($a);
    ?></pre>
    

    Output:

    $a->getit(); // accessor assign
    $a->hideme; // direct assign
    doobee($a); // accessor assign
    print_r($a);
    derived Object
    (
        [hideme] => direct assign
        [hideme:baseclass:private] => accessor assign
    )
    

    It's not just PHP that behaves this way; C# for instance does likewise.

    So I guess the take-away from all this is that it is not a good idea to try to change visibility of base class instance/members vars in derived classes.