简体   繁体   中英

PHP inheritance, parent functions using child variables

While reviewing some PHP code I've discovered a strange thing. Here is the simple example illustration of it:

File A.php:

<?php
class A{
    public function methodA(){
        echo $this->B;
    }
}
?>

File B.php:

<?php
    class B extends A{
        public $B = "It's working!";
    }
?>

File test.php:

<?php
    require_once("A.php");
    require_once("B.php");
    $b = new B();
    $b->methodA();
?>

Running test.php prints out "It's working!", but question is why is it working? :) Is this a feature or a bug? Method methodA in class A can also call methods that are in class B which should not work in OOP.

You're only instantiating class B . Ignore A for the moment, and pretend that methodA() is part of class B .

When class B extends A , it gets all of A 's functions. $this->B isn't evaluated until the code is running, not prior. Therefore no error occurs, and won't occur as $this->B exists in class B .

PHP is a dynamic language. The methods and data members are evaluated at runtime. When you call a method or access a member, PHP actually looks up a hashtable of sort to find out whether this method or member can be accessed on this object or not which can be anywhere in the inheritance hierarchy.

And not just inheritance, you can always assign arbitrary data to an object on runtime and the code inside the class will still be able to access it using $this->something where 'something' didn't even exist in class.

$this is just an object variable - a special one because it's the current one, but it still is just an object variable.

Because $B::B is a public member variable, it can be accessed from everwhere a reference to the instance of B is reachable, eg with a object variable.

As public members are accessible everywhere, any function, even from within A::methodA() it can be accessed.

So there is not much to actually wonder about. Class inheritance in your example only relates to the (invisible) passing of the object variable in form of the $this "parameter" when A::methodA() is invoked.

See the following example that probably makes it more visible:

function methodA($object) {
    echo $object->B;
}

class B {
    public $B = "It's working!";
    public function methodA() {
        methodA($this);
    }
}

由于PHP是一种动态语言,因此调用正在使用它的实例上可能存在的属性或方法没有任何问题(在本例中是子类B的实例)

PHP is a dynamic language. When methodA() is called on an instance of B the B's member $B does actually exist.

$a = new A();
$a->methodA();

would not work.

In some dynamic languages you can even define methods at runtime.

That makes sense to me; $B is made available in the resultant object by virtue of its appearing in class B. Since $this->B is evaluated at run-time, and the value is set before that (when class B is instantiated) it is found to be set correctly.

You can do this with methods as well, since their existence is not checked until they are executed (although it is usual in the case of methods to declare them abstract in the parent class, thus forcing the child to implement them).

This is how OOP is supposed to work. It might seem a little odd at first, since you'd think that A would have to know what $this->B is first (and indeed in some languages this would produce a compiler warning), but the behavior is correct since the subclass you're using is defining the variable that your function is looking for. If you called methodA() from an instance of A() , then you'd get an "undefined" error.

Now, what would be weird (read: wrong ) is if THIS worked:

class A {
   public $b = "Derp";
}
class B extends A {
  function sayIt() { echo $this->b; }
}
$a = new A();
$a->sayIt();

B类从A类扩展,因此它继承了A类的方法methodA()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM