覆盖私有方法时的奇怪行为 [英] Strange behavior when overriding private methods

查看:95
本文介绍了覆盖私有方法时的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下代码:

class foo {
    private function m() {
        echo 'foo->m() ';
    }
    public function call() {
        $this->m();
    }
}

class bar extends foo {
    private function m() {
        echo 'bar->m() ';
    }
    public function callbar() {
        $this->m();
    }
}

$bar = new bar;

$bar->call();
$bar->callbar();

现在,更改m()方法的可见性,我得到:
(对于public+,对于private-)

Now, changing the visibility of the m() method, I get:
(+ for public, - for private)

Visibility              bar->call()    bar->callbar() 
======================================================
-foo->m(), -bar->m()    foo->m()       bar->m()
-foo->m(), +bar->m()    foo->m()       bar->m()
+foo->m(), -bar->m()    ERROR          ERROR
+foo->m(), +bar->m()    bar->m()       bar->m()

(protected的行为类似于public).

我期望所有的行为都与声明为public时的行为相同.但是,尽管foo->call()bar->callbar()本质上是同一件事,但是根据foobarm()的可见性,它们会产生不同的结果.为什么会这样?

I was expecting everything to behave like it does when both are declared public. But although foo->call() and bar->callbar() are essentially the same thing, they yield different results depending on the visibility of m() in foo and bar. Why does this happen?

推荐答案

继承/覆盖私有方法

在PHP中,子类中的方法(包括私有方法)为:

Inheriting/overriding private methods

In PHP, methods (including private ones) in the subclasses are either:

  • 已复制;保持原始功能的范围.
  • 已替换(如果需要,可以覆盖").

您可以通过以下代码看到此内容:

You can see this with this code:

<?php
class A {
    //calling B::h, because static:: resolves to B::
    function callH() { static::h(); }
    private function h() { echo "in A::h"; }
}
class B extends A {
    //not necessary; just to make explicit what's happening
    function callH() { parent::callH(); }
}
$b = new B;
$b->callH();

现在,如果您覆盖私有方法,则其新作用域将不是A,它将成为B,并且调用将失败,因为A::callH()在作用域A中运行:

Now if you override the private method, its new scope will not be A, it will be B, and the call will fail because A::callH() runs in scope A:

<?php
class A {
    //calling B::h, because static:: resolves to B::
    function callH() { static::h(); }
    private function h() { echo "in A::h"; }
}
class B extends A {
    private function h() { echo "in B::h"; }
}
$b = new B;
$b->callH(); //fatal error; call to private method B::h() from context 'A'

调用方法

这里的规则如下:

Calling methods

Here the rules are as follows:

  • 查看对象的 actual class 的方法表(在您的情况下为bar).
    • 如果这产生了私有方法:
      • 如果定义方法的范围与调用函数的范围相同并且与对象的类相同,请使用它.
      • 否则,请在父类中查找一个私有方法,该私有方法的范围与调用函数之一的范围相同,并且名称相同.
      • 如果未找到满足上述要求之一的方法,则失败.
      • Look in the method table of the actual class of the object (in your case, bar).
        • If this yields a private method:
          • If the scope where the method was defined is the same as the scope of the calling function and is the same as the class of the object, use it.
          • Otherwise, look in the parent classes for a private method with the same scope as the one of the calling function and with the same name.
          • If no method is found that satisfies one of the above requirements, fail.
          • 如果方法的范围被标记为已更改,则我们可能已用公共/受保护的方法覆盖了私有方法.因此,在这种情况下,如果另外还有一个方法的名称与为调用函数的作用域定义的私有名称相同,请改用该方法.
          • 否则,请使用找到的方法.
          1. (均为私有)对于bar->call()call的范围为foo.调用$this->m()会在bar的方法表中为m查找,从而生成私有的bar::m().但是,bar::m()的范围不同于调用范围foo.遍历层次结构时会找到方法foo:m(),而将其代替.
          2. (foo中的私有,在bar中公共)call的范围仍然是foo.查找产生公共bar::m().但是,它的作用域被标记为已更改,因此在调用作用域foo的函数表中对方法m()进行了查找.这样会产生一个私有方法foo:m(),其范围与调用范围相同,因此将其代替.
          3. 这里什么也看不到,因为可见度降低而出错.
          4. (均为公共)call的范围仍为foo.查找产生公共bar::m().它的范围未标记为已更改(它们都是公开的),因此使用bar::m().
          1. (Both private) For bar->call(), the scope of call is foo. Calling $this->m() elicits a lookup in the method table of bar for m, yielding a private bar::m(). However, the scope of bar::m() is different from the calling scope, which foo. The method foo:m() is found when traversing up the hierarchy and is used instead.
          2. (Private in foo, public in bar) The scope of call is still foo. The lookup yields a public bar::m(). However, its scope is marked as having changed, so a lookup is made in the function table of the calling scope foo for method m(). This yields a private method foo:m() with the same scope as the calling scope, so it's used instead.
          3. Nothing to see here, error because visibility was lowered.
          4. (Both public) The scope of call is still foo. The lookup yields a public bar::m(). Its scope isn't marked as having changed (they're both public), so bar::m() is used.

          这篇关于覆盖私有方法时的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆