Could someone explain me, why is it possible to do the following in PHP, but, for example, not in C# or Java:
Class A {
protected $a = 'Howdy!';
}
Class B extends A {
public function howdy() {
$created = new A();
echo $created->a; <----- This is legal due to per-class visibility
}
}
$b = new B();
echo $b->howdy(); <----- Hence, no fatal error here
This behavior seems to be specified here, but I can't understand the fundamental reason behind this (to my mind, one can't simply implement the per-class
visibility instead of the per-instance
one without having a strong reason for that).
The reason it doesn't work is, as you specified, PHP implements access control on a class level, where other languages use an instance level approach.
Why is it useful? It allows your classes to operate on other instances of itself without exposing its private data. Let's take a simple value-object example:
class Int {
protected $value = 0;
public function __construct($value) {
$this->value = (int) $value;
}
public function add(Int $new) {
return new Int($new->value + $this->value);
}
}
$a = new Int(1);
$b = new Int(2);
$c = $a->add($b);
This lets you keep protected info encapsulated, yet still work with it across instances...
There are pros and cons to both approaches...
That is also possible in C# (and Java for that matter).
class A // declare new class type B
{
protected string a = "Howdy!"; // that has a protected member called `a`
}
class B : A // declare new type B which extends type A
{
public void howdy()
{
A created = new A();
Console.WriteLine(created.a); // no problem accessing a b/c B extends A
}
}
B bInst = new B(); // create a new instance of type B
bInst.howdy(); // invoke it's public method howdy()
Basically what is going on is this:
- class A contains a protected member called
a
which means it is visible in the scope of classes which extend A (in our case class B)
- class B extend a so it has access to it's protected members (in our case to
a
)
It is possible to do in both C# and Java as well. protected
means the variable is accessible from any subclass of A. B is a subclass of A, hence it can access the variable. There's no magic here.
The page you linked to has a section titled "Visibility from other objects" which states that:
Objects of the same type will have access to each others private and protected members even though they are not the same instances. This is because the implementation specific details are already known when inside those objects.
It wouldn't work if you'd done this:
$b = new B();
echo $b->a;
In your example, you're not accessing the $a member direct from B(). You're accessing it from an A() object that happens to have been instantiated from inside B().