Доступ к приватным свойствам суперкласса

karpov

Новичок
Привет! Заголовок смешной, но для меня откровение.
Мне не понятен механизм, по которому потомок связан с родительским классом. Всегда думал, что при создании объекта создается конечная сущность, то есть из двух классов формируется один (хотя понимал, что работал с несколькими типами).
Как вообще так происходит?

Код:
class Moo {
    private $var = 43;

    public function __construct() {}

    public function getVar() {
        return $this->var;
    }
}

class Boo extends Moo {
    public function __construct() {}
}

print (new Boo)->getVar(); //43
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
Связан наследованием. Надо пойти и прочитать книжку ;)

Есть разница в доступе через публичный геттер, или напрямую. Ее тебе и предстоит прочувствовать.
 

karpov

Новичок
karpov, в чём вопрос?
доступ к private $var происходит только внутри class Moo
$this является ссылкой на вызываемый объект. Тогда что есть объект, Moo и Boo ведь классы? Для меня объект, это конкретная реализация абстракции, имеющая состояние и поведение. Но в таком случае мое понятие плохо вкладывается в реальность. То есть, если он не имеет индивидуальную реализацию, то он пользуется это из родителей.

Связан наследованием. Надо пойти и прочитать книжку ;)
Есть разница в доступе через публичный геттер, или напрямую. Ее тебе и предстоит прочувствовать.
сейчас читаю книгу Мэтта Зандстра, и после прочтения главы 3, судя по всему, дальше мой вопрос там раскрыт не будет
я просто могу закрыть на это глаза и принять как должное, но это не совпадает с моими целями

говорят класс приватную переменную не наследует, тогда куда ссылается $this в методе getVar()
из первого кода видно, что она ссылается на приватное свойство суперкласса (что для меня странно, опять же, ведь оно не наследуется)
из второго кода видно, что ссылается на потомка
Код:
class Moo {
    protected $var = 'Moo';

    public function __construct() {}

    public function getVar() {
        return $this->var;
    }
}

class Boo extends Moo {
    protected $var = 'Boo';
    public function __construct() {}
}

print (new Boo)->getVar(); //Boo
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
karpov, надо было брать Котерова. Ты не понимаешь что такое наследование. Когда пишут $this, имеется в виду область видимости класса, а не метода. Публичный метод getVar предоставляет доступ к приватной переменной.

Понимаешь в чем дело. У тебя метод getVar() из родительского класса наследуется в дочернем классе, где тоже есть переменная $var. И метод getVar уже предоставляет доступ к ней. Наследование методов есть, наследования свойств - нет.

С protected свойствами немного все не так, как с private =)
 

WMix

герр M:)ller
Партнер клуба
говорят класс приватную переменную не наследует, тогда куда ссылается $this в методе getVar()
Код:
class Boo extends Moo {
  public function getVar() {
    return $this->var;
  }
}
а ты проверь
 

karpov

Новичок
Вот тут все логично, так как приватная переменная определена в классе Moo, поэтому метод внутри нее берет ее значение и возвращает
print (new Moo)->getVar();

Но как мы получаем доступ к приватной переменной принадлежащей классу Moo через экземпляр класса Boo?
На мой взгляд это работает так, класс который расширяет другой либо использует свои специализированные методы или свойства, либо использует реализацию суперкласса. Вот пример того, просто используем реализацию:
Код:
class Moo {
   //тут не объявлено свойство $var
    public function getVar() {
        return $this->var;
    }
}

class Boo extends Moo {
    protected $var = 'Boo';
}

print (new Boo)->getVar(); //Boo

Код:
class Boo extends Moo {
  public function getVar() {
    return $this->var;
  }
}
а ты проверь
Проверял ради интереса. Вот и я о том же.
Просто какая связь родительского метода с приватными полями родителя, которые опять же повторюсь не наследуются потомком.
 

WMix

герр M:)ller
Партнер клуба
а подумать? накуя тебе переменная на которую не сошлешься даже из публичного метода родительского класса? просто подумай.. дальнейшая дискусия безполезная (где приватность я тебе показал)! или задай вопрос иначе!
 

fixxxer

К.О.
Партнер клуба
Разберись лучше на примере Java. Там и литературы масса хорошей. В php модель в целом такая же, но из-за особенностей реализации можно много глупостей делать, в нормальном языке такая ерунда (//тут не объявлено свойство $var) даже не скомпилируется.
 

AnrDaemon

Продвинутый новичок
Прямо в документации на PHP приведены примеры, показывающие, от каких рук растут ноги.
 

karpov

Новичок
а подумать? накуя тебе переменная на которую не сошлешься даже из публичного метода родительского класса? просто подумай.. дальнейшая дискусия безполезная (где приватность я тебе показал)! или задай вопрос иначе!
Касаемо какого кода? Да практически и архитектурно неприемлемый, просто использовал в контексте дискуссии.
Вопрос не практического плана, скорее вопрос механизма работы.
Мой вопрос можно понять из этого кода, например:

Код:
<?php
/* Геттер определен в родительском классе и мы можем получить приватное значение родителя из дочернего класса (если он не переопределяет его) */

class Moo {
    private $var = 'Moo';
    public function getVar() {
        return $this->var;
    }
}

class Boo extends Moo {

}

print (new Boo)->getVar(); //Moo

/* Геттер определен в дочернем классе и не может получить приватное значение родителя */

class Moo {
    private $var = 'Moo';
}

class Boo extends Moo {
    public function getVar() {
        return $this->var;
    }
}

print (new Boo)->getVar(); // Notice: Undefined property: Boo::$var in /home/...
Вот тут и возникает вопрос, почему работает так? Почему есть доступ к приватному свойству родителя? Я уже это писал выше. Видимо вы не читали =)

Разберись лучше на примере Java. Там и литературы масса хорошей. В php модель в целом такая же, но из-за особенностей реализации можно много глупостей делать, в нормальном языке такая ерунда (//тут не объявлено свойство $var) даже не скомпилируется.
Да, стоит разобраться на Java литературе, там, как понимаю, ооп на переднем плане. Просто многие не зациклены на мелочах, и поверхностное понимание работы не мешает спокойно работать с ооп в PHP. + Моя ситуация вряд ли возникнет.
 

WMix

герр M:)ller
Партнер клуба
Вот тут и возникает вопрос, почему работает так?
а как оно по твоему должно работать? или какой ответ ожидаешь?
по мне раздел ооп в доках малоинформативный
ооп оно более менее везде одинаковый, есть особенности, но не в данном случае
Код:
print (new Boo)->getVar(); //Moo
ты обращаешься к публичному методу, это не запрещено, данный метод считывает в своем классе аттрибут, это тоже разрешено.
Код:
print (new Boo или Moo)->var;
а так ты ссылаешься на приватный аттрибут снаружи - болт!
 
Последнее редактирование:

karpov

Новичок
Код:
print (new Boo)->getVar(); //Moo
почему потомок имеет доступ к приватному полю родителя через наследуемый геттер родителя? ведь $this по сути ссылается на один объект, объект экземпляр класса Moo в котором:
1) нет приватного поля var
2) нет права доступа к приватным методам родителя
 

fixxxer

К.О.
Партнер клуба
karpov, короче, объясняю на пальцах, быстро и сумбурно =).
Начнем без наследования, пока считаем, что его нет, и есть только private и public.
У тебя есть класс Moo, который декларирует фактический интерфейс (состоящий из того, что у нас public): он умеет делать getVar():int. Что там внутри, return $this->var или return 43 - это никого снаружи не волнует, это детали реализации. Соответственно, поскольку детали реализации надо скрывать - для этого и есть private.

Теперь добавляем наследование, Boo extends Moo. Без ключевого слова protected - все остается как было, $this->var это деталь реализации конкретно Moo, а публичный getVar() - это и с точки зрения наследника публичный интерфейс, никакой разницы. При наследовании есть такое правило (Liskov substitution principle), что любой наследник обязан полностью поддерживать интерфейс базового класса, и при подстановке вместо базового класса его наследника все должно так же отлично работать - так что getVar() никуда не девается, он как был public так и остается. А вот чтобы при наследовании можно было делиться частью деталей реализации с наследниками - для этого и добавляется protected.

А что там технически куда ссылается - это уже следствия и детали реализации, это не так важно.
 

karpov

Новичок
примерно вроде разобрался, приватное поле тоже наследуется, полиморфизм потому что
просто мешало это осознать буквальное понимание слова 'перекрытие' в отношении свойств и методов.
теперь понимаю так: если потомок не переопределяет метод родителя, то он использует реализацию родителя, а методы родителя имеют доступ к своим приватным полям.
 

karpov

Новичок
и в добавок
Код:
var_dump(new Boo);
object(Boo)#1 (1) { ["var":"Moo":private]=> string(3) "Moo" }
 

AnrDaemon

Продвинутый новичок
Можно, я объясню быстро но не сумбурно?
Приватные аттрибуты и методы копируются в наследника.
Защищённые - наследуются.
В твоём примере, никаких (new Moo) не происходит, это всё бред собачий.
PHP:
<?php

class Moo
{
  private $var = 42;
  protected $bar = 3.14;

  public function getVar()
  {
    print "{$this->var}\n";
  }

  public function getBar()
  {
    print "{$this->bar}\n";
  }
}

class Boo extends Moo
{
  public function getVar()
  {
    $this->var = 43;
    print "{$this->var}\n";
    parent::getVar();
  }

  public function getBar()
  {
    $this->bar = 2.72;
    print "{$this->bar}\n";
    parent::getBar();
  }
}

$boo = new Boo();
$boo->getVar();
$boo->getBar();
 

karpov

Новичок
теперь вижу
$this->var = 43; не переопределяет приватное свойство, а объявляет новое в потомке
$this->bar = 2.72; переопределяет защищенное свойство

я думаю этот код просто обязан быть в каждом учебнике php
 
Сверху