5

我想在我的简单 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()

说得通。

我可以将范围更改为 public,但这看起来很难看:除了 Payment 之外没有人与before_save(). 恕我直言,最好保持私密。

如何让 Record 调用继承自 Record 的类的私有方法?

4

6 回答 6

8

向您的类添加一个虚拟before_save函数Record,将其可访问设置为受保护。现在所有继承自的类都Record将具有此功能,如果它们不覆盖它,它将什么也不做。如果他们覆盖它,它可以实现所需的功能。

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();
  }
}
于 2012-09-26T14:21:27.453 回答
7

获胜的答案没有回答问题。有关“公共”、“受保护”、“私人”和“最终”的信息应该可以在任何博客或书籍上获得。

这个问题询问如何使用继承类中的“私有”函数。这里的用例是你被迫使用设计不佳的第 3 方代码,不分青红皂白地使用私有函数,并且不得不找到使用私有函数的方法,或者分叉整个 repo。

这是问题的答案。

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 和父级的新实例的区别。不会从新实例的子级设置属性。

于 2020-05-20T19:48:33.343 回答
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......只是一个想法......

于 2012-09-26T14:18:58.783 回答
3

将范围更改为受保护:

http://php.net/manual/en/language.oop5.visibility.php

于 2012-09-26T14:18:40.433 回答
2

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

声明为 protected 的成员只能在类本身以及继承类和父类中访问

于 2012-09-26T14:23:12.643 回答
0
class test {

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

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

$testobj = new test;
echo $testobj->caller();

你会得到 5 作为输出。

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

于 2012-09-26T14:24:12.520 回答