Даже не знаю как по-другому назвать этот вопрос. Код: PHP: class Foo { private $bar = "baz"; public function getBar() { return $this->bar; } } class Bar extends Foo {} $o = new Bar; echo $o->getBar(); //baz Ну и собственно сабж.
Потому что getBar находится в классе Foo. Если бы getBar находился в классе Bar - не работало бы. Тип метода getBar тут роли не играет. Т.е. правило в том, что к приватному свойству могут обращаться только методы определенные в этом же классе - не выше и не ниже!
MiksIr так получается, что я обращаюсь к приватному свойству из "ниже", ведь обращение идет из экземпляра потомка
Немного видоизменим PHP: class Foo { private $bar = "baz"; public function getBar() { return $this->bar; } } class Bar extends Foo { private $bar = "I am Bar"; } $o = new Bar; echo $o->getBar(); //baz
Образаетесь к потомку, но метод _определен_ в родителе. Т.е. другими словами $this при обращении к приватным свойствам и методам указывает на методы и свойства того класса, в котором это $this написано. Иначе и быть не может, ибо если было бы иначе, то простое наследование ломало бы сразу класс родитель и можно было бы переопределять приватные свойства/методы. Так что если подумать - все логично.
Вот именно то, о чем я написал - если бы работало, как вам кажется - то можно было бы переопределить приватное свойство. Текущая логика защищает и от этого.
Поэкспериментируй с вариантами: PHP: <?php class Bar extends Foo { private $bar = "I am Bar"; public function getBar() { return $this->bar; } } PHP: <?php class Bar extends Foo { private $bar = "I am Bar"; public function getBar() { return parent::getBar(); } }
protected - это костыль. переменная с таким же именем находящаяся в той же зоне видимости, обращаются к ней через $this->bar... Вам не кажется что это бредом попахивает? PHP: <? class Foo { private $bar = "baz"; public function getBar() { return $this->bar; } } class Bar extends Foo { private $bar = "I am Bar"; public function getBar2() { return $this->bar; } } $o = new Bar; echo $o->getBar(); //baz echo $o->getBar2(); //I am Bar
всё правильно. если я не хочу, чтобы в моем классе данные меняли и внутренние методы вызывали - делаю всё приватное. если надо поделиться, то protected или public.
MiksIr каким бы это образом наследование ломало бы класс родитель, если бы приватные свойства не наследовались? Так получается, что как раз можно переопределить приватное свойство родителя, правда не напрямую, а через унаследованный метод. По логике приватные свойства и методы не должны наследоваться, прямо об этом говорится здесь http://ru2.php.net/manual/en/language.oop5.inheritance.php правда только про методы. А вот здесь http://ru2.php.net/manual/en/language.oop5.visibility.php написано, что и про потомков ни слова не сказано. Т.е. Bar вообще про $bar родителя ничего знать не должен, даже о его существовании. Т.о. ожидаемое поведение - это ошибка, что свойства $bar нет в классе Bar.
Согласен с ozland В моем понимании ООП приватное свойство на то и приватное, чтобы не наследоваться. Т.е. в первом примере для меня ожидаемым поведением была бы ошибка - "Свойство $bar не определено в классе Bar"
Простой пример. Есть сторонний класс PHP: class renderTbl { private $data = "Empty"; public function output() { if (!is_array($this->data)) echo $this->data; else { echo '<table><tr>'; foreach ($this->data as $ar) echo '<td>',$ar,'</td>'; echo '</tr></table>'; // еще 500 строк хитрого форматирования } } } Нафига писать свой велосипед для вывода массива как таблицы? Я беру и наследую его. PHP: class myTbl extends renderTbl { private $data; public function __construct() { // получаем $this->data из БД } public function filter($param) { $this->data = array('filtered'); // фильтрует $this->data по указанным параметрам } // еще дофига обработок $this->data } $o = new myTbl; $o->filter(array('f1'=>5)); //еще дофига обработок // в конце хотим вывести и ... echo $o->output(); // Empty // 3 часа ищем ошибку в своем коде
Значит еще раз. Публичное - внешний интерфейс. Протектед - доступное для расширения. Приватное - "спрятанная" логика класса. С этим все согласны? PHP: <?php class Super1 { private $key = "sdfgd"; public function Auth() { // используем $this->key где-то для авторизации } } $obj = new Super1(); $obj->Auth(); // все работает! class Super2 extend Super1 {}; $obj = new Super2(); $obj->Auth(); // к счастью тоже все работает, но если кому-то кажется, что $this должен брать что-то из Super2 - не будет работать Т.е. банально берем и ломаем работу внутренней логики класса, которая защищена private как раз для того, что бы ни один умник не мог это сломать. Где вы увидели возможность наследования private? PHP: <?php class Foo { private $bar = "baz"; public function getBar() { return $this->bar; } } class Bar extends Foo { private $bar = "I am Bar"; } $o = new Bar; echo $o->getBar(); //baz - нет наследования // но class Bar2 extends Foo { private $bar = "I am Bar"; public function getBar() { return $this->bar; } } $o = new Bar2; echo $o->getBar(); //I am Bar - это не "наследование", обращаемся к своему приватному свойству, о том, что там в Foo вообще не знаем Bar определен в классе родителя. Вбейте себе это в голову. Переопределите его в потомке - не будет знать. Пока он описан в родителе - будет знать. only be accessed by the class that defines the member. Не нужно мешать в одну кучу класс, где определен метод, и объект, у которого вы вызываете методы. При наследовании методы не "копируются" в потомка, они остаются на тех уровнях, что определены. Ну подумайте головой. Как вы вообще представляете иначе работу потомка? PHP: <?php class A { private function doOne() { // } private function doTwo() { /// } public function do() { $this->doOne(); $this->doTwo(); } } class B extend A {}; $objA = new A(); $objB = new B(); И что, по вашему $objA будет работать нормально, а $objB вообще работать не будет, ибо на $objB->do() будет выдаваться ошибка "а doOne и doTwo не определены"?
Получается, что при наследовании я должен знать как реализован родитель, чтобы не было подобных косяков, а это противоречит одному из основных принципов ООП. А вот, кстати, как комментируют это разработчики пхп - http://bugs.php.net/bug.php?id=26299 Примерно так же как и MiksIr -
Но не потому что PHP "странный", а потому что плохо понимаем ООП. Вы используете $data как расширяемый элемент. Значит он должен быть protected. Вообще-то могу лишь посоветовать - пока не почувствуете, что вам нужен private и только он - используйте protected.
Все с точностью до наоборот. Ваш пример как раз показывает, что вы не понимая чего-то полезли смотреть, как устроен класс - родитель, увидели в renderTbl некое $data и решили его использовать. А на основании чего вы решили это делать, кто вам это позволил делать, если $data приватное? Если бы кто-то хотел, что бы к $data был доступ, он бы сделал протектед или публичный геттер/сеттер... и вау, все бы заработало как ожидаемо. Если бы вы не знали, как реализован родитель, вы бы не лезли с работой с $data, и все было бы замечательно. Более того, если бы вы решили для своих целей в потомке назначить private $data (для других целей) не зная, что в родителе уже есть такое свойство, то все бы работало и ничего не сломалось.
Это специфика print_r, к данному вопросу отношения не имеет. print_r выводит приватные свойства всех "уровней" видимости... ну так его сделали. К вопросу отношения не имеет.