PHP5 member visibility

2019-09-16 19:31发布

问题:

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).

回答1:

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...



回答2:

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)


回答3:

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.



回答4:

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.



回答5:

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().