Как вызвать родительские методы PHP из унаследованного метода? - PullRequest
4 голосов
/ 25 ноября 2011

В PHP я пытаюсь ссылаться на метод, определенный в родительском классе объекта, из метода, унаследованного от родительского класса объекта.Вот код:

class base_class {
  function do_something() {
    print "base_class::do_something()\n";
  }
  function inherit_this() {
    parent::do_something();
  }
}
class middle_class extends base_class {
  function do_something() {
    print "middle_class::do_something()\n";
  }
}
class top_class extends middle_class {
  function do_something() {
    print "top_class::do_something()\n";
    $this->inherit_this();
  }
}

$obj = new top_class;
$obj->do_something();

Проблема заключается в том, что parent :: do_something () в методеиратский_вит () пытается найти родительский класс base_class, а не родительский объект фактического класса объекта, и в приведенном выше примере выбрасываетсяошибка.Есть ли что-то, что я могу написать вместо parent :: do_something (), которое будет вызывать middle_class :: do_something (), и это все равно будет работать даже в классах, которые расширяют (скажем) top_class?

Ответы [ 4 ]

2 голосов
/ 25 ноября 2011

Чтобы все заработало, вы можете изменить свой базовый класс следующим образом:

class base_class {
  function do_something() {
    print "base_class::do_something()\n";
  }

 function inherit_this() {
    $this->do_something();
 }
}

Тогда ваш top_clas будет вызывать attribute_this () вашего базового класса, но будет рекурсия: do_something () из вызовов top_class$ this-> inherit_this (), и в base_class вы снова вызываете $ this-> do_something () (в вашем базовом классе $ это будет ссылаться на ваш top_class).По этой причине вы будете снова и снова вызывать attribute.this ().

Вам следует переименовать методы, чтобы предотвратить это.

Обновление

Есливы хотите, чтобы base_class attribute_this () печатал "base_class :: do_something", вы можете изменить свой base_class следующим образом:

class base_class {
  function do_something() {
    print "base_class::do_something()\n";
  }

  function inherit_this() {
     base_class::do_something();
  }

}

В этом случае вы делаете статический вызов метода base_classсделай что-нибудь().Вывод: top_class::do_something() base_class::do_something()

Обновление 2

Что касается вашего комментария, вы можете изменить свой базовый класс следующим образом:

class base_class {
  function do_something() {
    print "base_class::do_something()\n";
  }
  function inherit_this() {    
    $par = get_parent_class($this);
    $par::do_something();
  }
}

Вы получаетекласс parrent $ this и затем вызов метода.Вывод будет: top_class::do_something() middle_class::do_something()

1 голос
/ 26 ноября 2011

Я начну с того, что скажу "Спасибо" grrbrr404. Он дал мне некоторые идеи и заставил меня начать в правильном направлении.

Решение, на котором я наконец остановился, было следующее:

function inherit_this() {
  $bt = debug_backtrace();
  call_user_func(array($this, get_parent_class($bt[1]['class']) . '::do_something'));
}

Это не красиво (я особенно ненавижу вызывать debug_backtrace() для этого), но оно сохраняет контекст объекта установленным в $ this и обрабатывает случай, когда метод вызывается из метода где-то в середине иерархии объектов.

Для тех, кто посчитал мой пример непонятным и / или хотел бы знать: «Зачем вам это делать?» Я прошу прощения и приведу следующий дополнительный пример, который, надеюсь, будет более иллюстративным и ближе к исходной проблеме. Это значительно дольше, но, надеюсь, показывает, почему я забочусь о правильном хранении $ this set, а также показывает, почему я не могу жестко закодировать какое-либо конкретное имя класса или использовать $ this-> method (). Избегание бесконечных циклов всегда приоритетно для меня. : -)

class class1_required_type { }
class class2_required_type { }
class class3_required_type { }
class class4_required_type { }

class class1 {
  protected $data = array();
  protected function checkType($name, $value, $requiredType) {
    print "In class1::checkType()\n";
    if (get_class($value) === $requiredType) {
      $backtrace = debug_backtrace();
      call_user_func(array($this, get_parent_class($backtrace[1]['class']) . "::mySet"), $name, $value);
    } else {
      throw new Exception(get_class($this) . "::mySet('" . $name . "') requires an object of type '" . $requiredType . "', but got '" . get_class($value) . "'");
    }
  }
  function mySet($name, $value) {
    print "In class1::mySet()\n";
    if ($name === 'class1_field') {
      $this->checkType($name, $value, 'class1_required_type');
    } else {
      $this->data[$name] = $value;
    }
  }
  function dump() {
    foreach ($this->data as $key => $value) {
      print "$key: " . get_class($value) . "\n";
    }
  }
}

class class2 extends class1 {
  function mySet($name, $value) {
    print "In class2::mySet()\n";
    if ($name === 'class2_field') {
      $this->checkType($name, $value, 'class2_required_type');
    } else {
      parent::mySet($name, $value);
    }
  }
}

class class3 extends class2 {
  function mySet($name, $value) {
    print "In class3::mySet()\n";
    if ($name === 'class3_field') {
      $this->checkType($name, $value, 'class3_required_type');
    } else {
      parent::mySet($name, $value);
    }
  }
}

class class4 extends class3 {
  function mySet($name, $value) {
    print "In class4::mySet()\n";
    if ($name === 'class4_field') {
      $this->checkType($name, $value, 'class4_required_type');
    } else {
      parent::mySet($name, $value);
    }
  }
}

$obj = new class4;
$obj->mySet('class3_field', new class3_required_type);
$obj->dump();

Я пытаюсь избежать дублирования функции "checkType ()", но все же обеспечиваю правильное поведение, даже когда иерархия становится произвольно большой.

Более элегантные решения, конечно, приветствуются.

0 голосов
/ 03 марта 2014
class base_class {
  function do_something() {
    print "base_class::do_something()\n";
  }
  function inherit_this() {
   //parent::do_something();
     $class = get_called_class();
     $class::do_something();
  }
}
0 голосов
/ 25 ноября 2011

Я не совсем уверен, что понимаю, почему ты так хочешь. Но я думаю, вы не можете этого сделать. Я понимаю, что вы сможете создать middle_class2 и унаследовать его, и тогда это будет middle_class2 вместо того, что вы называете middle_class?!

Итак, я думаю, вам нужно создать

  function inherit_this() {
    parent::do_something();
  }

в среднем классе.

Я думал о get_class ($ this) :: parent :: do_something () .. но это не сработало.

Просто чтобы быть уверенным .. Вы хотите вызвать middle_class :: do_something () правильно ??

...