どのように継承されたメソッド内からPHPの親メソッドを呼び出すのですか?

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();

問題は、inherit_this()のparent :: do_something()がオブジェクトの実際のクラスの親ではなく、base_classの親クラスを見つけようとしていることです。上記の例ではエラーが発生しています。 do_something()の代わりに書くことができますが、これはmiddle_class :: do_something()を呼びます。これはtop_classを拡張するクラスでも動作しますか?

4
php5を使用して、base_classのためにプライベートなメソッドを作ることはできませんか?これは、継承するクラスがメソッドをオーバーライドできないことを意味します。
追加された 著者 smack0007,
おそらく、私は実際に介入するクラスでメソッドをオーバーライドしたいと思っています。実際には、元のコードのポイントのほとんどです。私はこの例を書き直す必要があるかもしれませんが、それはもっと長くなるでしょう。
追加された 著者 Rick Koshi,

4 答え

これを動作させるには、base_classを次のように変更することができます:

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

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

Then your top_clas will call inherit_this() of your base class, but there will be a recursion: do_something() of top_class calls $this->inherit_this(), and in base_class you call again $this->do_something() (in your base class $this will reference to your top_class). Because of that, you will call inherit_this() over and over again.

それを防ぐためにメソッドの名前を変更する必要があります。

更新

そのbase_classをinherit_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();
  }

}

In this case you make a static call to the base_class method do_something(). The output is top_class::do_something() base_class::do_something()

更新2

あなたのコメントに関しては、base_classを次のように変更することができます:

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

You get the parrent class of $this and then call the method. Output will be: top_class::do_something() middle_class::do_something()

2
追加された
@RickKoshiああOK!私は更新する
追加された 著者 Grrbrr404,
うーん、PHPのOOPは少し奇妙です...あなたのデバッグの目的のために、あなたのクラスに特別なデバッグフラグを実装し、いくつかの "魔法の定数"を使うことができます。彼らと一緒に何が起こっているのかを見つけるのは簡単です。詳細についてはこのページをチェックしてください: davidwalsh.name/php-magic-constants
追加された 著者 Grrbrr404,
実際のコードでは、階層の各レベルごとに異なる方法でデータを操作するため、私は、それがmiddle_class :: do_something()を呼び出すようにしたいと思っています。すべてのレベルでinherit_this()を再実装する必要はありません。
追加された 著者 Rick Koshi,
これはうまくいくようですが、実際には$ thisのメソッドではなく、静的メソッドとして実際にはmiddle_class :: do_something()を呼び出すため、後で見つけにくいバグを導入するかもしれないという感覚を揺さぶることはできません。 $これはPHPの奇妙なスコープのためだけに設定されています。私はまだ壊れそうな例は考えていないが、私は緊張している。私はおそらく call_user_func(array($ this、get_parent_class($ this)。 ":: do_something"))が良いかもしれないと思います。
追加された 著者 Rick Koshi,
さらに反映すると、このメソッドは、inherit_this()がtop_classの先祖クラスによって定義されたメソッドによって呼び出された場合には機能しないことに気付きました。たとえば、 middle_class :: do_something()によって呼び出された場合、無限ループになります。しかし、私は、 debug_backtrace()(yuck)を含む解決策を考案しました。私は別の答えに詳細と長い例を書きました。
追加された 著者 Rick Koshi,

grrbrr404に「ありがとう」と言って始めます。彼は私にいくつかのアイデアを与え、私を正しい方向にスタートさせました。

私が最終的に解決した解決策は以下の通りです:

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

それはかなり複雑ではありません(私は特にこれのために debug_backtrace()を呼び出すことが嫌いです)、オブジェクトコンテキストを$ thisに設定しておき、途中のメソッドからメソッドが呼び出されるケースを処理しますオブジェクト階層。

For those who found my example confusing and/or wanted to know "Why would you want to do this?" I apologize, and provide the following additional example, which is hopefully more illustrative and closer to the original problem. It is considerably longer, but hopefully shows why I care about keeping $this set properly, and also shows why I can't hard-code any particular class name or use $this->method(). Avoiding infinite loops is always a priority with me. :-)

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()"関数の重複を避けようとしていますが、階層が任意に大きくなっても正しい動作を提供します。

より洗練されたソリューションはもちろん、大歓迎です。

1
追加された

私はあなたがなぜこのようにしたいのか理解しています。しかし、私はあなたがそれをすることはできないと思います。私はあなたがmiddle_class2を作り、そこから継承できるようになることを理解しています。それからあなたはmiddle_classのdosomethingの代わりにmiddle_class2でしょうか?

だから私はあなたが

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

middle_classにあります。

私はget_class($ this):: parent :: do_something()について考えましたが、うまくいきませんでした。

ちょうど確かに..あなたはmiddle_class :: do_something()を呼びたいと思っていますか?

0
追加された
$ thisのプロパティとメソッドに完全にアクセスできるように修正する
追加された 著者 Rick Koshi,
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
追加された
なぜこの作品がうまくいくのかの説明!
追加された 著者 PearsonArtPhoto,
PHP - 日本のコミュニティ [ja]
PHP - 日本のコミュニティ [ja]
4 参加者の

このグループではPHPについて話します。 パートナー:kotaeta.com