从继承的类调用私有方法

时间:2012-09-26 14:16:46

标签: php oop scope-resolution

我想在我的简单ORM中用PHP实现一个钩子系统:

class Record {
  public function save() {
    if (method_exists($this,"before_save")) {
      $this->before_save();
    }
    //...Storing record etc.
  }
}

class Payment extends Record {
  private function before_save() {
    $this->payed_at = time();
  }
}

$payment = new Payment();
$payment->save();

这会导致致命错误:

  

致命错误:调用私有方法Payment :: before_save()来自   

中的上下文“记录”

有道理。

我可以将范围更改为公开,但这看起来很难看:没有人但是付款与before_save()有关。最好保密,恕我直言。

如何在继承自Record?

的类上使Record调用为私有方法

6 个答案:

答案 0 :(得分:5)

before_save类添加一个虚拟Record函数,将其设置为受保护。现在,所有继承自Record的类都将具有此功能,如果它们不覆盖它,它将执行NOTHING。如果它们覆盖它,它可以实现所需的功能。

class Record {
  public function save() {
    $this->before_save();
    //...Storing record etc.
  }

  protected function before_save() {
     return;
  }
}

class Payment extends Record {
  protected function before_save() {
    $this->payed_at = time();
  }
}

答案 1 :(得分:4)

检查错误消息

Call to private method Payment::before_save() from context 'Record'

这意味着当您在Payment范围内时,您正试图调用Record中定义的函数。类Record没有before_save方法,因为继承链中的向上比定义函数的位置更强

换句话说,因为父子关系是Record (is parent of) PaymentPayment可以访问Records函数(由于从父级继承)但反之亦然(父级)不能“继承”子类功能)。你可以使你的函数受到保护,这将使它可以访问继承链的上下,但你可能想重新考虑体系结构并决定是否需要它。理想情况下你应该在Record中定义函数并且有它在Payment

中被覆盖

此外(我可能错了),但通常不需要明确检查method_exists,除非您正在创建一个可以重叠和/或生成运行时类的真正动态系统。如果你是从头开始定义一个基于类的系统,你知道如何拼接各个部分,通常你不需要在运行时检查method_exists ......只是一个想法.. < / p>

答案 2 :(得分:2)

答案 3 :(得分:2)

PHP中的可见性和继承规则:

  

声明受保护的成员只能在类本身以及继承和父类

中访问

答案 4 :(得分:1)

获胜者没有回答问题。有关“公开”,“受保护”,“私有”和“最终”的信息应可在任何博客或书籍上获得。

这个问题询问如何使用继承类中的“私有”功能。这里的用例是,您被迫使用设计不当,不加选择地使用私有函数的第三方代码,并且不得不寻找使用私有函数的方法,或者派生整个仓库。

这是问题的答案。

class foo {

    protected $text = "foo";

    private function bar($text)
    {
        return $text.'->'.$this->text;
    }
}

class fooChild extends foo{

    protected $text = "bar";

    public function barChild()
    {
        $r = new \ReflectionMethod(parent::class, 'bar');
        $r->setAccessible(true);
        //return $r->invokeArgs(new foo(), ['output']); // output->foo
        return $r->invokeArgs($this, ['output']);//output->bar
    }
}

echo (new fooChild())->barChild();

使用ReflectionMethod类,可以从继承类调用私有方法。您可以看到使用$ this和父对象的新实例的区别。不会从新实例的子级设置属性。

答案 5 :(得分:0)

班级考试{

private function pri($val){
    return $val;
}

function caller(){
   return $this->pri(5);
}

}

$ testobj = new test; echo $ testobj-&gt; caller();

您将获得5作为输出。

通过这种方式,您可以访问类的私有函数。