【问题标题】:php oops: visibilityphp 哎呀:可见性
【发布时间】:2012-08-01 04:39:08
【问题描述】:

我正在用 PHP 修改我的 OOP 概念。我在这里有一个简单的 php 代码来练习可见性。

当我在 Big_Animal 中将 $name 声明为私有时,

1)为什么当我尝试从类外部为 $name 分配不同的值时它不会引发错误(即 $lion->name="King")?

2)为什么当我尝试在 Lion 类中重新分配 $name 时它不会引发错误(即 $this->name="John")。

据我所知,我很困惑,私有属性只能在定义该属性的类中访问。

我不清楚的另一件事是受保护的属性。据我了解,受保护的属性只能在类本身及其子类中访问。它的孙子类可以访问它吗?

谢谢。

<?php
abstract class Big_Animal{

 private $name="Mary";

  abstract public function Greet();

 public function Describe(){
    return "name: ".$this->name;
}

public function __set($name,$value){
    $this->name=$value;
}

public function __get($name){
    return $this->name;
}
}

class Lion extends Big_Animal{


public function Greet(){
    $this->name="John"; //no error for this
    return " roar!";
}



public function Describe(){
        return parent::Describe()." I'm a Lion!";
    }
}


$lion = new Lion();
$lion->name="King";  //no error for this
echo $lion->Describe();
echo $lion->Greet();

?>

【问题讨论】:

  • 如果删除 __set 函数会发生什么?我在我的手机上,所以无法尝试自己

标签: php oop visibility


【解决方案1】:
  1. 您的魔术方法访问器(__set 和 __get)在基类抽象类中是公共的。当您直接访问该属性时,它们会写入私有数据。尝试注释掉魔术方法并查看。然后,输出为“name: Mary I'm a Lion! roar!”。

  2. 将此添加为 Lion::Describe() 中的第一条语句:

    echo "狮子的名字:" 。 $this->name 。 "\n";

    如您所见,现在的输出是:“Lion's name: King”。 $this->name="John";和 $lion->name="King";正在修改 Lion 类对象的公共属性。不幸的是,您可以同时拥有同名的公共和私有属性,但您可以。它们只是不同的变量(在不同的范围内)。

  3. 可以从孙子访问受保护的属性。您的大部分财产都应该受到保护,除非您有非常充分的理由来保护它(因此使用私有)。公共属性在大型项目中使用不多(取决于您的风格)。我宁愿坚持使用显式访问器。随着项目的进展和变得越来越复杂,您会很高兴选择对每个变量使用访问器。我更喜欢使用生成器来为您生成脚手架访问器。它节省了大量时间,减少了错误,并使访问器的创建成本更低(因此更常见)。

更新(对以下评论的回应): 1) 和 2) 您没有收到错误,因为您在上面 2) 中列出的两个实例中都在编辑 Public 变量。试试 var_dump($lion):

object(Lion)#1 (2) {
  ["name":"Big_Animal":private]=>
  string(4) "Mary"
  ["name"]=>
  string(4) "John"
}

此外,如果您向 Lion 类显式添加私有或受保护的成员变量,您将收到预期的错误。我同意你的观点,这不是很直观,但似乎是 PHP 中的当前现实。

3) http://www.ibm.com/developerworks/opensource/library/os-php-7oohabits/ 有一个为私有成员变量编写公共访问器的示例(尽管我再次建议为受保护的成员变量编写公共访问器)。

【讨论】:

  • 我试过 1),没错。我得到“名字:玛丽,我是狮子!咆哮!”但没有错误。在 2)是的,我得到“狮子的名字:国王”。但是,“不幸的是,您可以同时拥有同名的公共和私有属性,但您可以。它们只是不同的变量(在不同的范围内),这是什么意思。”我在这里看不到任何公共财产。关于 3) 我不知道显式访问器。我得读一读。谢谢。
  • @vaanipala:我已经通过对这些 cmets 的回复更新了答案。希望对您有所帮助。
【解决方案2】:

因为你使用的是__set()的魔法方法

__set() 在将数据写入不可访问的属性时运行。

也可以通过$lion-&gt;name获取值,因为你也使用__get()

【讨论】:

    【解决方案3】:

    详细说明我的评论...您正在使用一个名为 __set 的函数,它的作用是每次您尝试为此类的未知属性设置值时,都会调用此特定函数。

    在您的函数中,您总是将私有字段名称更改为提供的值。由于此类可以访问其字段,因此已设置。

    即使你写了 $lion->foo = "bar",名字也会被设置为 bar,因为你的函数 __set

    【讨论】:

    • 我试过你说的。我评论了 __get 和 __set。输出是“名字:玛丽,我是狮子!吼!”。没有错误,虽然我有 $lion = new Lion(); $lion->name="国王"; $lion->foo="bar";回声$狮子​​->描述(); echo $lion->Greet();
    • @vaanipala:Php 在很多方面都有点奇怪,请检查您是否显示错误,检查错误日志,因为这可能是无声错误等。或者您可能忘记保存或发生其他事情。我不确定“试图设置一个不存在的属性”是否被归类为表演障碍。可能不是。欢迎来到可爱的 php 世界 :)
    • 好的,我在 php.ini 中取消了 display_errors 的注释,重新启动了 apache web 服务器并检查了 apache 的错误日志。仍然没有错误。
    【解决方案4】:

    我认为你的问题的答案是here

    抽象方法不能是私有的,因为根据定义它们必须是私有的 由派生类实现。如果你不希望它公开,它 需要保护,这意味着它可以被派生看到 类,但没有其他人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-23
      • 1970-01-01
      • 1970-01-01
      • 2019-02-13
      • 2011-04-13
      • 1970-01-01
      相关资源
      最近更新 更多