За последние 24 часа нас посетили 53207 программистов и 1713 роботов. Сейчас ищут 896 программистов ...

Почему это работает?

Тема в разделе "Прочие вопросы по PHP", создана пользователем ozland, 14 мар 2011.

  1. ozland

    ozland Активный пользователь

    С нами с:
    15 июл 2008
    Сообщения:
    16
    Симпатии:
    0
    Даже не знаю как по-другому назвать этот вопрос. Код:
    PHP:
    1.  
    2. class Foo {
    3.     private $bar = "baz";
    4.  
    5.     public function getBar() {
    6.         return $this->bar;
    7.     }
    8. }
    9.  
    10. class Bar extends Foo {}
    11.  
    12. $o = new Bar;
    13. echo $o->getBar(); //baz
    14.  
    Ну и собственно сабж.
     
  2. Апельсин

    Апельсин Активный пользователь

    С нами с:
    20 мар 2010
    Сообщения:
    3.645
    Симпатии:
    2
    Да вроде так и должно, хотя я тут не силен. Метод getBar не приватный то, не смотря на private $bar
     
  3. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Потому что getBar находится в классе Foo. Если бы getBar находился в классе Bar - не работало бы.
    Тип метода getBar тут роли не играет. Т.е. правило в том, что к приватному свойству могут обращаться только методы определенные в этом же классе - не выше и не ниже!
     
  4. ozland

    ozland Активный пользователь

    С нами с:
    15 июл 2008
    Сообщения:
    16
    Симпатии:
    0
    MiksIr
    так получается, что я обращаюсь к приватному свойству из "ниже", ведь обращение идет из экземпляра потомка
     
  5. ozland

    ozland Активный пользователь

    С нами с:
    15 июл 2008
    Сообщения:
    16
    Симпатии:
    0
    Немного видоизменим
    PHP:
    1.  
    2. class Foo {
    3.     private $bar = "baz";
    4.  
    5.     public function getBar() {
    6.         return $this->bar;
    7.     }
    8. }
    9.  
    10. class Bar extends Foo {
    11.     private $bar = "I am Bar";
    12. }
    13.  
    14. $o = new Bar;
    15. echo $o->getBar(); //baz
    16.  
     
  6. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Образаетесь к потомку, но метод _определен_ в родителе.
    Т.е. другими словами $this при обращении к приватным свойствам и методам указывает на методы и свойства того класса, в котором это $this написано. Иначе и быть не может, ибо если было бы иначе, то простое наследование ломало бы сразу класс родитель и можно было бы переопределять приватные свойства/методы. Так что если подумать - все логично.
     
  7. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Вот именно то, о чем я написал - если бы работало, как вам кажется - то можно было бы переопределить приватное свойство. Текущая логика защищает и от этого.
     
  8. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Поэкспериментируй с вариантами:
    PHP:
    1. <?php
    2. class Bar extends Foo {
    3.      private $bar = "I am Bar";
    4.  
    5.      public function getBar() {
    6.          return $this->bar;
    7.      }
    8.  }
    PHP:
    1. <?php
    2. class Bar extends Foo {
    3.      private $bar = "I am Bar";
    4.  
    5.      public function getBar() {
    6.          return parent::getBar();
    7.      }
    8.  }
     
  9. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    тут должен быть амбар. полюбас.
     
  10. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    И знамя ведущего говнокодера переходит... переходит...
     
  11. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    любите вы недороботки и ошибки выставлять за фичи :D
     
  12. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Каким должен быть код, чтобы переменная бар была переопределена?
     
  13. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Расскажите отличие private от protected :)
     
  14. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    protected - это костыль.

    переменная с таким же именем находящаяся в той же зоне видимости, обращаются к ней через $this->bar...

    Вам не кажется что это бредом попахивает?

    PHP:
    1. <?
    2. class Foo {
    3.      private $bar = "baz";
    4.  
    5.      public function getBar() {
    6.          return $this->bar;
    7.      }
    8.  }
    9.  
    10.  class Bar extends Foo {
    11.      private $bar = "I am Bar";
    12.  
    13.      public function getBar2() {
    14.          return $this->bar;
    15.      }
    16.  }
    17.  
    18.  $o = new Bar;
    19.  echo $o->getBar(); //baz
    20.  echo $o->getBar2(); //I am Bar
     
  15. iliavlad

    iliavlad Активный пользователь

    С нами с:
    24 янв 2009
    Сообщения:
    1.689
    Симпатии:
    4
    всё правильно. если я не хочу, чтобы в моем классе данные меняли и внутренние методы вызывали - делаю всё приватное. если надо поделиться, то protected или public.
     
  16. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    трололо
    MiksIr
    не ведись
     
  17. ozland

    ozland Активный пользователь

    С нами с:
    15 июл 2008
    Сообщения:
    16
    Симпатии:
    0
    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.
     
  18. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    Согласен с ozland

    В моем понимании ООП приватное свойство на то и приватное, чтобы не наследоваться. Т.е. в первом примере для меня ожидаемым поведением была бы ошибка - "Свойство $bar не определено в классе Bar"
     
  19. ozland

    ozland Активный пользователь

    С нами с:
    15 июл 2008
    Сообщения:
    16
    Симпатии:
    0
    Простой пример.
    Есть сторонний класс
    PHP:
    1.  
    2. class renderTbl {
    3.     private $data = "Empty";
    4.  
    5.     public function output() {     
    6.         if (!is_array($this->data))
    7.             echo $this->data;
    8.         else {
    9.             echo '<table><tr>';
    10.            
    11.             foreach ($this->data as $ar)
    12.                 echo '<td>',$ar,'</td>';
    13.            
    14.             echo '</tr></table>';
    15.  
    16.             // еще 500 строк хитрого форматирования
    17.         }      
    18.     }
    19. }
    20.  
    Нафига писать свой велосипед для вывода массива как таблицы? Я беру и наследую его.
    PHP:
    1.  
    2. class myTbl extends renderTbl {
    3.     private $data;
    4.    
    5.     public function  __construct() {
    6.         // получаем $this->data из БД
    7.     }
    8.    
    9.     public function filter($param) {
    10.         $this->data = array('filtered');
    11.         // фильтрует $this->data по указанным параметрам
    12.     }
    13.    
    14.     // еще дофига обработок $this->data
    15. }
    16.  
    17. $o = new myTbl;
    18. $o->filter(array('f1'=>5));
    19. //еще дофига обработок
    20. // в конце хотим вывести и ...
    21. echo $o->output(); // Empty
    22. // 3 часа ищем ошибку в своем коде
    23.  
     
  20. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Значит еще раз. Публичное - внешний интерфейс. Протектед - доступное для расширения. Приватное - "спрятанная" логика класса. С этим все согласны?
    PHP:
    1. <?php
    2. class Super1 {
    3.   private $key = "sdfgd";
    4.  
    5.   public function Auth() {
    6.      // используем $this->key где-то для авторизации
    7.   }
    8. }
    9. $obj = new Super1();
    10. $obj->Auth();
    11. // все работает!
    12.  
    13. class Super2 extend Super1 {};
    14. $obj = new Super2();
    15. $obj->Auth();
    16. // к счастью тоже все работает, но если кому-то кажется, что $this должен брать что-то из Super2 - не будет работать
    Т.е. банально берем и ломаем работу внутренней логики класса, которая защищена private как раз для того, что бы ни один умник не мог это сломать.

    Где вы увидели возможность наследования private?
    PHP:
    1. <?php
    2.   class Foo {
    3.      private $bar = "baz";
    4.  
    5.      public function getBar() {
    6.          return $this->bar;
    7.      }
    8.  }
    9.  
    10.  class Bar extends Foo {
    11.      private $bar = "I am Bar";
    12.  }
    13.  
    14.  $o = new Bar;
    15.  echo $o->getBar(); //baz - нет наследования
    16.  // но
    17.  class Bar2 extends Foo {
    18.      private $bar = "I am Bar";
    19.  
    20.      public function getBar() {
    21.          return $this->bar;
    22.      }
    23.  }
    24.  $o = new Bar2;
    25.  echo $o->getBar(); //I am Bar - это не "наследование", обращаемся к своему приватному свойству, о том, что там в Foo вообще не знаем
    Bar определен в классе родителя. Вбейте себе это в голову. Переопределите его в потомке - не будет знать. Пока он описан в родителе - будет знать. only be accessed by the class that defines the member. Не нужно мешать в одну кучу класс, где определен метод, и объект, у которого вы вызываете методы. При наследовании методы не "копируются" в потомка, они остаются на тех уровнях, что определены.

    Ну подумайте головой. Как вы вообще представляете иначе работу потомка?
    PHP:
    1. <?php
    2. class A {
    3.   private function doOne() {
    4.     //
    5.   }
    6.   private function doTwo() {
    7.     ///
    8.   }
    9.   public function do() {
    10.     $this->doOne();
    11.     $this->doTwo();
    12.   }
    13. }
    14.  
    15. class B extend A {};
    16. $objA = new A();
    17. $objB = new B();
    18.  
    И что, по вашему $objA будет работать нормально, а $objB вообще работать не будет, ибо на $objB->do() будет выдаваться ошибка "а doOne и doTwo не определены"?
     
  21. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Значит разработчик стороннего класса не предназначал свой класс для наследования.
     
  22. ozland

    ozland Активный пользователь

    С нами с:
    15 июл 2008
    Сообщения:
    16
    Симпатии:
    0
    Получается, что при наследовании я должен знать как реализован родитель, чтобы не было подобных косяков, а это противоречит одному из основных принципов ООП.
    А вот, кстати, как комментируют это разработчики пхп - http://bugs.php.net/bug.php?id=26299
    Примерно так же как и MiksIr -
     
  23. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Но не потому что PHP "странный", а потому что плохо понимаем ООП.
    Вы используете $data как расширяемый элемент. Значит он должен быть protected. Вообще-то могу лишь посоветовать - пока не почувствуете, что вам нужен private и только он - используйте protected.
     
  24. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Все с точностью до наоборот.

    Ваш пример как раз показывает, что вы не понимая чего-то полезли смотреть, как устроен класс - родитель, увидели в renderTbl некое $data и решили его использовать. А на основании чего вы решили это делать, кто вам это позволил делать, если $data приватное? Если бы кто-то хотел, что бы к $data был доступ, он бы сделал протектед или публичный геттер/сеттер... и вау, все бы заработало как ожидаемо.

    Если бы вы не знали, как реализован родитель, вы бы не лезли с работой с $data, и все было бы замечательно. Более того, если бы вы решили для своих целей в потомке назначить private $data (для других целей) не зная, что в родителе уже есть такое свойство, то все бы работало и ничего не сломалось.
     
  25. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Это специфика print_r, к данному вопросу отношения не имеет. print_r выводит приватные свойства всех "уровней" видимости... ну так его сделали. К вопросу отношения не имеет.