Reputation: 1875
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.
Upvotes: 14
Views: 3429
Reputation: 197624
$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, e.g. 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);
}
}
Upvotes: 3
Reputation: 15369
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();
Upvotes: 1
Reputation: 20430
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).
Upvotes: 1
Reputation: 26330
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.
Upvotes: 1
Reputation: 35533
As PHP is a dynamic language, there is nothing wrong with calling properties or methods that may exist on the instance that is using it (in this case an instance of subclass B)
Upvotes: 2
Reputation: 267049
Class B extends from Class A, hence it inherits the method methodA()
from class A.
Upvotes: 0
Reputation: 163270
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
.
Upvotes: 12
Reputation: 35126
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.
Upvotes: 6