Хорошо, позвольте мне попробовать [Опять]
В основном оба метода существуют бок о бок.
Под частной структурой подразумевается, что эта вещь (метод или свойство) не видна, недоступна или доступна для записи ничем, кроме класса, в котором она была определена. Поэтому дети не могут ни использовать ее, ни модифицировать ее. Это поведение частного.
Причина (причина), лежащая в основе концепции, заключается в том, чтобы гарантировать определенную функциональность (или значение, свойства) независимо от того, как расширяется класс. Это хорошо, потому что при разработке родительского класса мы можем не знать, как он будет использоваться какими-либо расширяющими классами, и могут существовать функциональные возможности, которые являются критическими и не должны изменяться. Это дает нам возможность гарантировать это в нашем коде, не зная реализации потомков.
Одна из причин, по которой они могут существовать бок о бок, заключается в том, что внутри дочернего класса при вызове $this->foo()
нет никакой двусмысленности относительно того, что foo вызывается только как общедоступная версия C::foo()
видимая для class C
(дочерний элемент ) учебный класс.
class A {
private function foo() {
echo "A!";
}
public function parentTest() { //formerly A::test()
//if we used C::foo() from here Overriding A::foo().
//having a concept of private would lose all meaning
//because we would be allowing the child to modify
// the functionality of private A:foo()
$this->foo();
}
}
class C extends A {
public function foo() {
echo 'C!';
}
public function childTest() {
//A::foo() cannot be used from here
//so PHP knows to use C::foo()
$this->foo();
}
}
Короче говоря, для дочернего класса C::foo()
доступен только один Foo, поэтому его нельзя спутать с частной версией A::foo()
PHP. Таким образом, оба метода могут существовать без переопределения дочерним методом метода родителей.
Не позвольте мне запутать вас больше здесь, потому что в некотором смысле метод childs перекрывает родителей. Мы можем увидеть это, если позвоним $obj->foo()
из глобального пространства. Если мы не определяем foo в дочернем элементе C
, мы получаем ошибку. Но если мы определяем публичный в C
, он используется. Еще одна вещь, которая показывает, что она перезаписывает (в некоторых отношениях), если мы устанавливаем копию родительского элемента A::foo()
как окончательную. В этом случае, если мы попытаемся определить C::foo()
, мы получим ошибку, как и следовало ожидать.
Но (вот важная часть), ни один из них не влияет на функциональность личных вещей в том, что касается родителей, и поэтому они не нарушают частный принцип.
Теперь для родителей вызовите свой собственный метод.
Здесь большинство людей смущаются, и вы спрашиваете:
При вызове того, что для всех намерений и целей, C :: test, почему он предпочитает закрытый A :: foo публичному C :: foo
Это не так, потому что вы вызываете приватный метод A::foo()
из другого метода A::test()
в том же классе class A
, где был определен приватный метод.
Если бы он предпочел метод потомка своему собственному, тогда не было бы смысла иметь частную видимость, потому что мы бы просто нарушили его, позволив ребенку изменить метод. Другими словами, мы будем использовать функциональность ребенка вместо функции, помеченной как private.
Действительно, это единственный разумный способ, которым это могло бы работать. В том же ключе, если вы перезаписываете A::test()
с тем же точным кодом, но в class C
или C::test()
тот же самый вызов теперь будет обращаться к общедоступному методу, потому что это единственный видимый внутри класса C
, где новый вызов пришел от.
Summery
Это единственный логический способ работы private, если классу, определяющему приватный метод, было разрешено использовать дочернее определение метода, это полностью устранило бы причину наличия приватности в первую очередь, и я бы не стал пытаться объяснить это. Потому что тогда это будет просто то, что мы называем protected
, которое у нас уже есть.
UPDATE
Так, иногда он вызывает метод из своего собственного, иногда он вызывает метод из родительского.
Не совсем верно. Вызовы приватного метода (foo), поступающие от метода, определенного только в parent (A), всегда будут обращаться к приватному методу parent (A) (foo). Вызовы, поступающие от метода, определенного в child (C), получат доступ либо к методу Child (C) (foo), либо к ошибке при попытке доступа к закрытому методу Parent (A) (foo).
Case1: , если A:foo()
вызывается из A
(независимо от экземпляра), он будет вызывать свой закрытый метод независимо от того, существует ли метод из дочернего класса, который переопределяет foo
. В этом контексте is called from within A
означает вызов из любого метода, определенного в A и не перезаписанного в B. Вызов foo
происходит из класса A
.
class A {
private function foo() {
echo "A!\n";
}
public function parentTest() {
//parentTest Is not overwritten in C
//so when C::parentTest() is called that call goes here
//inside the A class where foo is defined.
$this->foo();
}
}
class C extends A {
private function foo() {
echo "C!\n";
}
}
//this is called from A
//because there is no method named parentTest outside of A
(new C)->parentTest(); //A!
См. Ошибку, которую вы совершаете: (new C)->parentTest();
физически не существует в C. Он включен в C по наследству, и его область действия все еще находится в родительском классе, когда речь идет о частном доступе, потому что foo
и parentTest
существуют только в классе A
.
Поэтому он имеет доступ к закрытым методам класса A, потому что это класс A, даже если объект является экземпляром C.
Вы можете полностью удалить класс C. Поведение будет таким же.
class A {
private function foo() {
echo "A!\n";
}
public function parentTest() {
$this->foo();
}
}
//the path the code follows to execute is identical to the previous example.
(new A)->parentTest(); //A!
Case2: , если A:foo()
вызывается напрямую от дочернего элемента A
и не перезаписан , вы получаете доступ к закрытому методу ошибки. Звонок на foo
поступает из класса C
.
class A {
private function foo() {
echo "A!\n";
}
}
class C extends A {
public function childTest() {
//A::foo() is not visable, and no C::foo() exists
$this->foo();
}
}
//this comes direct from Class C,
//which cannot directly access Class A's private scope
(new C)->childTest(); //Error: Call to private method A::foo()
Case3: , если A:foo()
вызывается из дочернего элемента A
, а переопределяется , он вызывает метод Child. is called from a child of A
означает любой метод, определенный в C
, независимо от того, переопределяет ли он (открытый / защищенный) метод A
. Звонок foo
поступает из класса C
.
class A {
private function foo() {
echo "A!\n";
}
}
class C extends A {
public function foo() {
echo "C!\n";
}
public function test() {
//C::test() calls it's foo function
//because the call comes from here not inside the A class
$this->foo();
}
}
//this is called from C, the method childTest is defined in C
(new C)->childTest(); //C!
Это верно независимо от того, существует ли публичный метод с тем же именем (test) в родительском элементе.
class A {
private function foo() {
echo "A!\n";
}
public function test() {
//this is a public method that is overwritten as normal by C
//when this is called the, C::test() is called as normal
//because of inheritance
$this->foo();
}
}
class C extends A {
public function foo() {
echo "C!\n";
}
public function test() {
//C::test() calls it's foo function
//again the call comes from here not inside the A class
$this->foo();
}
}
//This is called from C, because test is overwritten in C and is visible (public)
(new C)->test(); //C!
Как я показал в первом примере в этом Обновлении (за исключением его обратной версии), вы можете полностью удалить класс A, и способ выполнения кода не изменится:
class C{
private function foo() {
echo "C!\n";
}
public function test() {
$this->foo();
}
}
//the code executes along the same path even without A
(new C)->test(); //C!
Вкратце: наследование - это не простая операция копирования и вставки. Код из A не копируется и не вставляется в C. Каждый класс все еще существует, просто A разделяет все, что доступно с C (защищено, общедоступно)
Надеюсь, это поможет, это лучшее, что я могу сделать.