質問

必要な機能を備えたいくつかのクラスがありますが、組織用に個別に保存したい場合は、両方を持つようにクラスを拡張できますか?

すなわち class a extends b extends c

編集:クラスを一度に1つずつ拡張する方法は知っていますが、複数のベースクラスを使用してクラスを即座に拡張する方法を探しています - AFAIK PHPではこれを行うことはできませんが、頼らずにそれを回避する方法があるはずです class c extends b, class b extends a

役に立ちましたか?

解決

編集に答える:

複数継承を偽造したい場合は、Magic Function __Call()を使用できます。

これは醜いですが、クラスAユーザーの観点からは機能します。

class B {
    public function method_from_b($s) {
        echo $s;
    }
}

class C {
    public function method_from_c($s) {
        echo $s;
    }
}

class A extends B
{
  private $c;

  public function __construct()
  {
    $this->c = new C;
  }

  // fake "extends C" using magic function
  public function __call($method, $args)
  {
    $this->c->$method($args[0]);
  }
}


$a = new A;
$a->method_from_b("abc");
$a->method_from_c("def");

印刷「ABCDEF」

他のヒント

2つの基本クラスを拡張するクラスを作成することはできません。あなたは持っていませんでした。

// this is NOT allowed (for all you google speeders)
Matron extends Nurse, HumanEntity

ただし、次のように階層を持つことができます...

Matron extends Nurse    
Consultant extends Doctor

Nurse extends HumanEntity
Doctor extends HumanEntity

HumanEntity extends DatabaseTable
DatabaseTable extends AbstractTable

等々。

特性を使用できます。これは、PHP 5.4から利用できることを願っています。

特性は、PHPなどの単一の相続言語でのコード再利用のメカニズムです。特性は、開発者がさまざまなクラスの階層に住んでいるいくつかの独立したクラスで自由にメソッドセットを再利用できるようにすることにより、単一の継承のいくつかの制限を減らすことを目的としています。特性とクラスの組み合わせのセマンティクスは、複雑さを軽減し、複数の継承とミキシンに関連する典型的な問題を回避する方法で定義されます。

彼らは、より良い構成と再利用をサポートする可能性があることで認識されているため、Perl 6、Scheak、Scala、Slate、Fortressなどの新しいバージョンの言語に統合されます。特性もJavaとC#に移植されています。

詳しくは: https://wiki.php.net/rfc/traits

クラスは、単なる方法のコレクションであることを意図したものではありません。クラスは、状態(フィールド)と行動(方法)の両方が状態を変える抽象的な概念を表すことになっています。継承を使用するためにいくつかの望ましい動作を取得するためだけに使用するだけの悪いOO設計のように聞こえ、多くの言語が複数の継承を許可する理由です。「スパゲッティ継承」を防ぐために、つまり、それぞれが必要な方法があるために3つのクラスを拡張し、終わります。 100のメソッドと20のフィールドを継承するクラスですが、そのうちの5つだけを使用しています。

すぐにミックスインを追加する計画があると思います。

しかし、それまでは、受け入れられている答えを持って行きます。それを少し抽象化して、「拡張可能な」クラスを作成できます。

class Extendable{
  private $extender=array();

  public function addExtender(Extender $obj){
    $this->extenders[] = $obj;
    $obj->setExtendee($this);
  }

  public function __call($name, $params){
    foreach($this->extenders as $extender){
       //do reflection to see if extender has this method with this argument count
       if (method_exists($extender, $name)){
          return call_user_func_array(array($extender, $name), $params);
       }
    }
  }
}


$foo = new Extendable();
$foo->addExtender(new OtherClass());
$foo->other_class_method();

このモデルでは、「他のクラス」が$ fooについて「知る」ことができることに注意してください。他のクラスには、この関係を設定するには、「Setextendee」と呼ばれるパブリック機能が必要です。次に、メソッドが$ fooから呼び出された場合、内部で$ fooにアクセスできます。ただし、実際の拡張クラスのように、プライベート/保護された方法/変数にアクセスすることはできません。

@Franckによる現在受け入れられている回答は機能しますが、実際には複数の継承ではなく、範囲外で定義されたクラスの子のインスタンスであり、またあります。 __call() 速記 - ただの使用を検討してください $this->childInstance->method(args) 「拡張」クラスの外部クラスクラスメソッドが必要な場所。

正確な答え

いいえ、それぞれ、実際にはそうではありません のマニュアル extends キーワード 言う:

拡張クラスは常に単一の基本クラスに依存します。つまり、多重継承はサポートされていません。

本当の答え

しかし、@adamが正しく提案したように、これは複数の階層継承を使用することを禁止しません。

あるクラスを拡張し、別のクラスと一緒に別のクラスを拡張できます。

これに関する非常に簡単な例は次のとおりです。

class firstInheritance{}
class secondInheritance extends firstInheritance{}
class someFinalClass extends secondInheritance{}
//...and so on...

重要な注意点

ご存知かもしれませんが、 プロセスに含まれるすべてのクラスを制御できる場合、階層により複数の(2+)腸のみを行うことができます - つまり、このソリューションを組み込みのクラスやクラスで編集できないクラスで適用することはできません。それを行いたい場合は、@Franckソリューション - チャイルドインスタンスが残ります。

...そして最後に、いくつかの出力を使用した例:

class A{
  function a_hi(){
    echo "I am a of A".PHP_EOL."<br>".PHP_EOL;  
  }
}

class B extends A{
  function b_hi(){
    echo "I am b of B".PHP_EOL."<br>".PHP_EOL;  
  }
}

class C extends B{
  function c_hi(){
    echo "I am c of C".PHP_EOL."<br>".PHP_EOL;  
  }
}

$myTestInstance = new C();

$myTestInstance->a_hi();
$myTestInstance->b_hi();
$myTestInstance->c_hi();

出力

I am a of A 
I am b of B 
I am c of C 

特性を基本クラスとして使用します。次に、親クラスでそれらを使用します。拡張します。

trait business{
  function sell(){

  }

  function buy(){

  }

  function collectMoney(){
  }

}

trait human{

   function think(){

   }

   function speak(){

   }

}

class BusinessPerson{
  use business;
  use human;
  // If you have more traits bring more
}


class BusinessWoman extends BusinessPerson{

   function getPregnant(){

   }

}


$bw = new BusinessWoman();
$bw ->speak();
$bw->getPregnant();

現在、ビジネスウーマンが論理的に継承されたビジネスと人間の両方を参照してください。

<?php
// what if we want to extend more than one class?

abstract class ExtensionBridge
{
    // array containing all the extended classes
    private $_exts = array();
    public $_this;

    function __construct() {$_this = $this;}

    public function addExt($object)
    {
        $this->_exts[]=$object;
    }

    public function __get($varname)
    {
        foreach($this->_exts as $ext)
        {
            if(property_exists($ext,$varname))
            return $ext->$varname;
        }
    }

    public function __call($method,$args)
    {
        foreach($this->_exts as $ext)
        {
            if(method_exists($ext,$method))
            return call_user_method_array($method,$ext,$args);
        }
        throw new Exception("This Method {$method} doesn't exists");
    }


}

class Ext1
{
    private $name="";
    private $id="";
    public function setID($id){$this->id = $id;}
    public function setName($name){$this->name = $name;}
    public function getID(){return $this->id;}
    public function getName(){return $this->name;}
}

class Ext2
{
    private $address="";
    private $country="";
    public function setAddress($address){$this->address = $address;}
    public function setCountry($country){$this->country = $country;}
    public function getAddress(){return $this->address;}
    public function getCountry(){return $this->country;}
}

class Extender extends ExtensionBridge
{
    function __construct()
    {
        parent::addExt(new Ext1());
        parent::addExt(new Ext2());
    }

    public function __toString()
    {
        return $this->getName().', from: '.$this->getCountry();
    }
}

$o = new Extender();
$o->setName("Mahdi");
$o->setCountry("Al-Ahwaz");
echo $o;
?>

(図書館/フレームワークとは対照的に)プロジェクトの継承を思いとどまらせる記事をいくつか読み、agaisntインターフェイスをプログラムすることを奨励しましたが、実装に対してはありません。
また、作曲によってOOを提唱します。クラスAとBの関数が必要な場合は、このタイプのメンバー/フィールドを持つCを作成します。

class C
{
    private $a, $b;

    public function __construct($x, $y)
    {
        $this->a = new A(42, $x);
        $this->b = new B($y);
    }

    protected function DoSomething()
    {
        $this->a->Act();
        $this->b->Do();
    }
}

複数の継承は、インターフェイスレベルで機能しているようです。 PHP 5.6.1でテストを行いました。

これが作業コードです:

<?php


interface Animal
{
    public function sayHello();
}


interface HairyThing
{
    public function plush();
}

interface Dog extends Animal, HairyThing
{
    public function bark();
}


class Puppy implements Dog
{
    public function bark()
    {
        echo "ouaf";
    }

    public function sayHello()
    {
        echo "hello";
    }

    public function plush()
    {
        echo "plush";
    }


}


echo PHP_VERSION; // 5.6.1
$o = new Puppy();
$o->bark();
$o->plush();
$o->sayHello(); // displays: 5.6.16ouafplushhello

私はそれが可能だとは思いませんでしたが、SwiftMailerソースコード、swift_transport_iobufferクラスで偶然見つけました。これには次の定義があります。

interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream

まだ遊んでいませんでしたが、共有するのは面白いかもしれません。

「多重相続」の問題を解決しました。

class Session {
    public $username;
}

class MyServiceResponsetype {
    protected $only_avaliable_in_response;
}

class SessionResponse extends MyServiceResponsetype {
    /** has shared $only_avaliable_in_response */

    public $session;

    public function __construct(Session $session) {
      $this->session = $session;
    }

}

これにより、MyServiceresponsetypeがセッションを単独で処理できることを拡張するSession Response内でセッションを操作する力があります。

PHP 5.4の時点で発表されたPHPの特性を使用してそれを行うことができます

これがあなたのための簡単なチュートリアルです、 http://culttt.com/2014/06/25/php-tarts/

PHPはまだ複数のクラスの継承をサポートしていませんが、複数のインターフェイス継承をサポートしています。

見る http://www.hudzilla.org/php/6_17_0.php いくつかの例について。

PHPは複数の継承を許可しませんが、複数のインターフェイスの実装を行うことができます。実装が「重い」場合は、提供してください 骨格の実装 個別のクラスの各インターフェイスについて。そうすれば、できます これらの骨格の実装にすべてのインターフェイスクラスを委任します 経由 オブジェクトの封じ込め.

Not knowing exactly what you're trying to achieve, I would suggest looking into the possibility of redesigning you application to use composition rather than inheritance in this case.

Always good idea is to make parent class, with functions ... i.e. add this all functionality to parent.

And "move" all classes that use this hierarchically down. I need - rewrite functions, which are specific.

If you want to check if a function is public see this topic : https://stackoverflow.com/a/4160928/2226755

And use call_user_func_array(...) method for many or not arguments.

Like this :

class B {
    public function method_from_b($s) {
        echo $s;
    }
}

class C {
    public function method_from_c($l, $l1, $l2) {
        echo $l.$l1.$l2;
    }
}

class A extends B {
    private $c;

    public function __construct() {
        $this->c = new C;
    }

    public function __call($method, $args) {
        if (method_exists($this->c, $method)) {
            $reflection = new ReflectionMethod($this->c, $method);
            if (!$reflection->isPublic()) {
                throw new RuntimeException("Call to not public method ".get_class($this)."::$method()");
            }

            return call_user_func_array(array($this->c, $method), $args);
        } else {
            throw new RuntimeException("Call to undefined method ".get_class($this)."::$method()");
        }
    }
}


$a = new A;
$a->method_from_b("abc");
$a->method_from_c("d", "e", "f");

One of the problems of PHP as a programming language is the fact that you can only have single inheritance. This means a class can only inherit from one other class.

However, a lot of the time it would be beneficial to inherit from multiple classes. For example, it might be desirable to inherit methods from a couple of different classes in order to prevent code duplication.

This problem can lead to class that has a long family history of inheritance which often does not make sense.

In PHP 5.4 a new feature of the language was added known as Traits. A Trait is kind of like a Mixin in that it allows you to mix Trait classes into an existing class. This means you can reduce code duplication and get the benefits whilst avoiding the problems of multiple inheritance.

Traits

class A extends B {}

class B extends C {}

Then A has extended both B and C

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top