Вызовите приватный метод из унаследованного класса

Я хочу реализовать систему ловушек в моем простом 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();

Это приводит к фатальной ошибке:

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

Имеет смысл.

Я мог бы изменить область действия на общедоступную, но это кажется уродливым: никто, кроме Payment, не имеет никакого отношения к before_save(). Лучше всего оставить в покое, ИМХО.

Как я могу заставить Record вызывать закрытый метод класса, унаследованного от Record?

5 ответов

Решение

Добавить манекен 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();
  }
}

Победивший ответ не отвечает на вопрос. Информация о "общедоступном", "защищенном", "частном" и "окончательном" должна быть доступна в любом блоге или книге.

Этот вопрос касается того, как использовать "частную" функцию из наследуемого класса. Пример использования здесь заключается в том, что вы вынуждены использовать сторонний код, который плохо спроектирован, неизбирательно использует частные функции и сталкиваетесь с необходимостью либо найти способ использования частной функции, либо форкнуть все репо.

Вот ответ на вопрос.

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 и нового экземпляра родительского элемента. Свойства не будут устанавливаться из дочернего элемента из нового экземпляра.

Проверьте сообщение об ошибке

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

Это означает, что вы пытаетесь вызвать функцию, определенную в Payment пока ты внутри Record, Учебный класс Record не имеет before_save метод, потому что он находится выше в цепочке наследования, чем где определена функция.

Другими словами, так как отношение родитель-ребенок Record (is parent of) Payment, Payment имеет доступ к Records функции (в силу наследования от родителя), но не наоборот (родитель не может "наследовать" функции дочернего класса). Вы можете сделать свою функцию защищенной, что даст ей доступ вверх и вниз по цепочке наследования, но вы можете переосмыслить архитектуру и решить, хотите ли вы ее так. В идеале вы должны иметь функцию, определенную в Record и переопределить его в Payment

Также (и я могу ошибаться с этим), но проверка явно method_exists обычно не требуется, если вы не создаете действительно динамическую систему, в которой классы времени выполнения могут перекрываться и / или генерироваться. Если вы определяете систему, основанную на классах, с нуля и знаете, как объединять различные части, обычно вам не нужно проверять во время выполнения, method_exists...просто мысль..

Измените область действия на защищенную:

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

Видимость и правила наследования в PHP:

Члены, объявленные защищенными, могут быть доступны только внутри самого класса, а также унаследованными и родительскими классами.

Тест класса {

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

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

}

$ testobj = новый тест; echo $testobj->caller();

Вы получите 5 в качестве выхода.

Таким образом, вы можете получить доступ к закрытой функции класса.

Другие вопросы по тегам