PHP5 成员可见性

Posted

技术标签:

【中文标题】PHP5 成员可见性【英文标题】:PHP5 member visibility 【发布时间】:2012-05-26 02:36:02 【问题描述】:

有人可以解释一下,为什么可以在 php 中执行以下操作,但是,例如,不能在 C# 或 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

这种行为似乎是由here, 指定的,但我无法理解其背后的根本原因 (在我看来,不能简单地实现per-class 可见性per-instance 中的一个没有充分的理由)。

【问题讨论】:

我可能遗漏了一些东西,但为什么这不可能呢?您正在从对象调用公共函数。该函数创建一个对象(内部),该对象与它有权访问的对象中的变量相呼应。有什么问题? 为什么会出现致命错误?没有成员可见性错误。 B 可以看到所有Apublicprotected 询问为什么某些东西在 Lang X 中有效或无效,但在 Lang Y 中无效通常是没有意义的。它们是不同的语言,因此它们可能会有所不同。在这种特殊情况下,您的假设是错误的。所以这里没有问题。 @Nanne 这可能,但其他几种语言禁止这样做,这导致了我的困惑(例如***.com/questions/10657545/…)无论如何,我对这个决定背后的根本原因很感兴趣(这不是你在早上喝咖啡时发明的那种东西)。 @Gordon 我同意你的第一句话,但我的哪个假设到底是错误的? 【参考方案1】:

它不起作用的原因是,正如您所指定的,PHP 在类级别实现访问控制,而其他语言使用实例级别的方法。

为什么有用?它允许您的类在不暴露其私有数据的情况下对其自身的其他实例进行操作。让我们举一个简单的值对象示例:

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

这让您可以封装受保护的信息,但仍然可以跨实例使用它...

这两种方法各有利弊...

【讨论】:

【参考方案2】:

这在 C#(和 Java 中)也是可能的。

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

基本上是这样的:

A 类包含一个名为aprotected 成员,这意味着它在扩展A 的类的范围内是可见的(在我们的例子中是B 类) B 类扩展了 a,因此它可以访问受保护的成员(在我们的例子中是 a

【讨论】:

我猜这是不正确的,见***.com/questions/10657545/… 这是不正确的。 PHP 在类级别而不是实例级别实现安全性。其他语言在实例级别实现它。两者各有利弊……【参考方案3】:

在 C# 和 Java 中也可以这样做。 protected 表示该变量可以从 A 的任何子类访问。B 是 A 的子类,因此它可以访问该变量。这里没有魔法。

【讨论】:

我猜不是。见***.com/questions/10657545/…【参考方案4】:

您链接到的页面有一个标题为"Visibility from other objects" 的部分,其中指出:

相同类型的对象可以访问彼此的私有成员和受保护成员,即使它们不是相同的实例。这是因为在这些对象内部时,特定于实现的细节是已知的。

【讨论】:

是的,但是这个决定背后的原因是什么?为什么有人会发明这种规则并将其添加到语言规范中?我当然理解PHP 设计师有权做他们想做的事,但是这种行为与其他语言中的类似行为不同,这背后应该有一些强有力的理由。【参考方案5】:

如果你这样做了,那就不行了:

$b = new B();
echo $b->a;

在您的示例中,您没有直接从 B() 访问 $a 成员。您正在从恰好从 B() 内部实例化的 A() 对象访问它。

【讨论】:

以上是关于PHP5 成员可见性的主要内容,如果未能解决你的问题,请参考以下文章

Delphi的类和对象- 封装(成员可见性)

Spark 作业中的 Scala 成员字段可见性

非原子时,C++ 成员更新关键部分内的可见性

[GO]可见性

kotlin访问控制符可见性

面向对象语言成员变量方法可见性在继承中的变化