$ This behavior on inherited methods

It always seemed to me that I understand how OOP works (and I have been using it for many years), but sometimes I understand that some concepts are still not so clear to me.

I just stumbled upon this question about method visibility in PHP. The accepted answer explains that a private method cannot be overridden by a child class in PHP. Ok, that makes sense. However, this example made me think of the internal inheritance mechanism in PHP, and the $this way behaves according to the inherited methods.

Consider this code ( an example from the PHP manual also included in the question mentioned above):

 class Bar { public function test() { $this->testPrivate(); $this->testPublic(); } public function testPublic() { echo "Bar::testPublic\n"; } private function testPrivate() { echo "Bar::testPrivate\n"; } } class Foo extends Bar { public function testPublic() { echo "Foo::testPublic\n"; } private function testPrivate() { echo "Foo::testPrivate\n"; } } $myFoo = new foo(); $myFoo->test(); /* Output: Bar::testPrivate Foo::testPublic */ 

Now consider this excerpt from the PHP manual :

The pseudo-variable $ this is available when the method is called from the context of the object. $ is a reference to the calling object (usually the object to which the method belongs, but possibly another object if the method is called statically from the context of the secondary object).

The explanation says that " $this is a reference to the caller", which is equal to $myFoo . So I expected that $myFoo->test() would always call Foo::testPrivate and never Bar::testPrivate (unless $myFoo was an instance of Bar ). I tested $this with get_class , and it always returns Foo , even from inside Bar::testPrivate and Bar::test . However, $this behaves like an instance of Bar when Bar::test calls $this->testPrivate() .

This is really confusing, and I'm trying to figure out why this works!

I thought that the inherited methods ( public or protected ) were somehow copied from the database to the child class. Private methods will not be copied at all. But this example shows that it does not work like that. It appears that the Foo instance stores the internal instance of Bar and delegates method calls to it if necessary.

I'm trying to find out something here, and I only find out when it all seems to me. This is not there. After writing all this, I think I can summarize it with two questions:

  • Can someone briefly explain how inheritance works inside PHP? Or at least point me to an article or documentation about this?

  • Is the behavior or $this discussed here present in other OO languages, or is it specific to PHP?

+2
source share
2 answers

Inheritance in PHP works the same way as in most object-oriented languages.

When you have a β€œvirtual” method, the method is not attached directly to the caller. Instead, each class contains a small lookup table that says "this method name is associated with this implementation." So, when you say $this->testPublic() , what actually happens is that PHP:

  • Gets a virtual table for the current class
  • View virtual table table for testPublic in this table
  • Invokes a method for which search points

Since Foo overrides testPublic , its virtual table contains an entry for testPublic pointing to Foo::testPublic .

Now that private methods, the behavior is different. Since, as you read correctly, private methods cannot be overridden, calling a private method never leads to finding a virtual table. That is, private methods cannot be virtual and must always be defined in the class that uses them.

So the effect is that the name is bound during the declaration: all Foo methods will call Foo::testPrivate when they say $this->testPrivate , and all Bar methods will call Bar::testPrivate .

To summarize, arguing that "inherited methods are copied for a child" are incorrect. In fact, it happens that a child element begins by filling its parent name class table with the names of the method names, and then adds its own functions and replaces any overridden entries. When you call $this->something , this lookup table is requested for the current class of objects. Therefore, if $this is an instance of Foo , and Foo overrides testPublic , you get Foo::testPublic . If $this is an instance of Bar , you will get Bar::testPublic .

+5
source

Well, private methods and properties are exactly that - private. For all purposes and goals, you can consider them "internal", which means internal to the class in which they are defined. This means that they are never inherited and can never be redefined.

Thus, when using $this in combination with a method or private property, it will always be a method or property within the same class as the reference to $this . This is because $this , called inside the parent class, cannot access private methods or properties in another class (since they are private) even from child classes.

Hope this helps.

+2
source

Source: https://habr.com/ru/post/909285/


All Articles