代码之家  ›  专栏  ›  技术社区  ›  Mike B

从类A的类B(扩展类A)调用静态方法

  •  5
  • Mike B  · 技术社区  · 16 年前

    在一次实践测试中有一个有趣的问题,我不明白答案。以下代码的输出是什么:

    <?php
    class Foo {
        public $name = 'Andrew';
    
        public function getName() {
            echo $this->name;
        }
    }
    
    class Bar extends Foo {
        public $name = 'John';
    
        public function getName() {
            Foo::getName();
        }
    }
    
    $a = new Bar;
    $a->getName();
    ?>
    

    最初,我认为这会产生一个错误,因为静态方法不能引用$this(至少在php5中)。我自己测试了这个,它实际上输出了约翰。

    我在脚本末尾添加了foo::getname();并得到了我所期望的错误。所以,当您从扩展您所调用的类的类中调用静态方法时,会发生什么变化?

    有人能详细解释一下这里到底发生了什么吗?

    5 回复  |  直到 16 年前
        1
  •  2
  •   Szymon Rozga    16 年前

    $this传递给在其上下文中调用该方法的对象。所以:$a->getname()是$a。$fooInstance->getname()中的$fooInstance是$fooInstance。如果设置了$this(在对象$a的方法调用中),并且我们调用了一个静态方法,$this仍然被分配给$a。

    似乎使用这个特性会产生很多混乱。:)

        2
  •  7
  •   Paul Dixon    16 年前

    foo::getname()使用的是旧的php4样式 scope resolution operator 允许调用重写的方法。

    在php5中,您将使用 parent :改为:getname()。

    如果您希望扩展,而不是完全重写基类的行为,这是很有用的,例如,这可能会使它更清晰。

    class Bar extends Foo {
        public $name = 'John';
    
        public function getName() {
            echo "My name is ";
            parent::getName();
        }
    }
    
        3
  •  4
  •   Ulf    16 年前

    如果调用绑定到另一个对象的静态方法,该方法将在当前对象的上下文中执行。允许访问$this对象。

    从子类内部调用超类方法的更好方法是:

    parent::getName();
    
        4
  •  1
  •   notruthless    16 年前

    当你打电话 $a->getName() 你在引用一个特定的对象, $a ,哪个等级的 Bar “约翰”也回来了。

    Foo::getName() 在函数外部无效,因为没有特定对象。

    我不确定它在PHP中是否有效,但是如果您 铸造 超类的对象,如 (Foo)$a->getName() 然后你会得到“安德鲁”作为你的结果。你还是会谈论具体的对象( $A )但在这种情况下 Foo . ( 注意,你一般不想这样做 )

        5
  •  1
  •   Shane H    16 年前

    有时程序员用代码比用英语更好地解释事情!

    这里首先讨论的是重载的概念。当您实例化BAR时,它的getname()方法将重载foo中同名的方法。

    超载是OOD的一个重要组成部分。

    但是,调用父类(foo)中存在的方法版本通常很有用。

    下面是一个例子:

    class Dog
    {
       public function getTag()
       {
          return "I'm a dog.";
       }
    }
    
    class Skip extends dog
    {
       public function getTag()
       {
          return Dog::getTag() . " My name is Skip.";
          // I'm using Dog:: because it matches your example. However, you should use parent:: instead.
       }
    }
    
    $o = new Skip();
    echo $o->getTag(); // Echo's: "I'm a dog. My name is Skip."
    

    显然,这是一个非常狭隘的例子,但它说明了一点。

    基类是类型的最一般的实现。在本例中,它是“dog”,您希望将信息放入该类型的所有实例都通用的基类中。这可以防止每个派生类中的重复(如“skip”)。

    您的脚本可能无意中利用了这个特性。