За последние 24 часа нас посетили 20265 программистов и 1006 роботов. Сейчас ищут 369 программистов ...

Старый вопрос о Перегрузке наследованием

Тема в разделе "Прочие вопросы по PHP", создана пользователем Вероломство, 24 мар 2021.

  1. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    Пару лет назад возникал уже вопрос такой, но практики применения не было и поэтому был забыт:

    PHP:
    1. class A
    2. {
    3.     private $data = [];
    4.  
    5.     public function __set($name, $value)
    6.     {
    7.         $this->data[$name] = $value;
    8.     }
    9. }
    10.  
    11. class B extends A
    12. {
    13.     protected $b;
    14.     private $c;
    15.  
    16.     public function __construct()
    17.     {
    18.         $this->a = 'Несуществующее';
    19.         $this->b = 'Защищённое';
    20.         $this->c = 'Приватное';
    21.     }
    22. }
    23.  
    24. var_dump(new B);
    Выхлоп

    Код (Text):
    1. object(B)[2]
    2.   protected 'b' => string 'Защищённое' (length=20)
    3.   private 'c' => string 'Приватное' (length=18)
    4.   private 'data' (A) =>
    5.     array (size=1)
    6.       'a' => string 'Несуществующее' (length=28)
    Как видим при записи в недоступные (защищённые или приватные) свойства не отработала магия методом __set(), то есть документация подсовывает нам лажу:

    Код (Text):
    1. Метод __set() будет выполнен при записи данных в недоступные (защищённые или приватные) или несуществующие свойства.
    Я правильно понимаю, что нас обманули и запись производится ТОЛЬКО В НЕСУЩЕСТВУЮЩИЕ?

    Кто-то пояснит мне убогому, что происходит? )))

    p.s. для тех, кто сомневается, то дам оригинал

    __set() is run when writing data to inaccessible (protected or private) or non-existing properties

    как видим ИЛИ указывает на то, что защищённые и приватные могут существовать и __set() будет выполнен, но этого не происходит
     
    #1 Вероломство, 24 мар 2021
    Последнее редактирование: 24 мар 2021
  2. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.591
    Симпатии:
    360
    @Вероломство, создай приватное свойство в классе A и из класса B что-нить в него запиши.
     
  3. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    так написано в документации по методу __set()? :)

    если ты о том, что __set() работает по месту проживания в A, то как он при создании экземпляра B отработал на несуществующем свойстве и поместил его в массив, который в A o_O

    согласно документации туда же должны были улететь приват и протектед
     
    #3 Вероломство, 24 мар 2021
    Последнее редактирование: 24 мар 2021
  4. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.591
    Симпатии:
    360
    Недоступное свойство - это какое свойство?
    privat, объявленное в классе и используемое в этом-же классе - доступное.
    protected, объявленное в родительском классе и используемое в наследнике - доступное.
    privat, объявленное в родительском классе и используемое в наследнике - недоступное.
    protected, объявленное в классе и используемое извне классе - недоступное.
     
    Вероломство нравится это.
  5. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    всё, догнал :)

    меня вот это путало - НЕДОСТУПНОЕ, особенно в этой части: protected, объявленное в родительском классе и используемое в наследнике - доступное

    так как согласно той же документации - протектед виден РОДИТЕЛЯМ, вот тут я жоска путался

    спасибо за расклад, всё ок, порешали...
    --- Добавлено ---
    @Sail а если протектед объявлено в наследнике, то какое оно по отношению к родителю, доступное?
     
  6. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.591
    Симпатии:
    360
    Согласно документации - protected виден наследникам, а не родителям.
    Базовый класс ничего не знает о свойствах и методах, объявленных в наследнике.
    Следовательно, если protected (свойство или метод) объявлен в наследнике - в методах базового класса он недоступен.
    На этот случай есть абстрактные методы, например.
    Объявляешь в базовом классе абстрактный метод, или базовый класс - реализующим некий интерфейс (не забыть класс объявить абстрактным, если не включать реализацию методов интерфейса) и из других методов базового класса можешь вызывать этот "абстрактный" метод.
    Вызываться будет реализованный в наследнике, так как создан объект класса-наследника и из него уже можно вызвать методы (protected и public базового класса).
    Ведь в случае абстрактного базового класса - его экземпляр объекта не создаётся.
    Этот, реализованный в наследнике метод свободно может обращаться со свойствами, объявленными в этом-же "наследнике" и с доступными (публичными и защищёнными) свойствами и методами базового класса.
     
  7. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    @Sail а если объявлено в наследнике, то какое оно по отношению к родителю, доступное?
    вот поэтому и путаница, потому что официальная документация гласит:

    Модификатор protected (защищённый) разрешает доступ самому классу, наследующим его классам и родительским классам.

    Как тебе такой поворот? :)

    Почему протектед не улетел в массив родителя по __set() назревает вопрос тогда :(
     
  8. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.591
    Симпатии:
    360
    Имеется ввиду, что из метода родительского класса можно обратиться к protected-свойству класса-наследника.
    Но только из экземпляра объекта класса-наследника.
    PHP:
    1. class A
    2. {
    3.     public function foo()
    4.     {
    5.         return $this->boo;
    6.     }
    7. }
    8.  
    9. class B extends A
    10. {
    11.     protected $boo = 333;
    12.     public function getBoo()
    13.     {
    14.         return $this->boo;
    15.     }
    16. }
    17.  
    18. $boo = new B();
    19. $foo = $boo->foo();
    20. $zoo = $boo->getBoo();
    21. var_dump($foo, $zoo);
    --- Добавлено ---
    Потому что он доступен в объекте, созданном из класса-наследника (B).
     
    Вероломство нравится это.
  9. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    короче ясно: маслом по маслу, ок, спс... :)
     
  10. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.591
    Симпатии:
    360
    Скорее уж на случай перегрузки protected/public свойств и/или методов в наследнике.