PHP에서 1 개 이상의 클래스를 사용하여 클래스를 연장 할 수 있습니까?

StackOverflow https://stackoverflow.com/questions/356128

  •  21-08-2019
  •  | 
  •  

문제

필요한 기능이 있지만 조직을 위해 별도로 저장하려는 여러 클래스가 있다면 클래스를 확장하여 둘 다 가질 수 있습니까?

class a extends b extends c

편집 : 수업을 한 번에 하나씩 확장하는 방법을 알고 있지만 여러 기본 클래스를 사용하여 클래스를 즉시 확장하는 방법을 찾고 있습니다. class c extends b, class b extends a

도움이 되었습니까?

해결책

편집에 응답 :

여러 상속을 실제로 가짜로 만들고 싶다면 마법 함수 __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"인쇄

다른 팁

두 개의 기본 클래스를 연장하는 수업을 가질 수 없습니다. 당신은 가질 수 없었습니다.

// 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, Squeak, 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();

이 모델에서 "Otherclass"는 $ 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

나는 그것이 가능하다고 생각하지 않았지만 Swift_transport_iobuffer 클래스에서 Swiftmailer 소스 코드를 우연히 발견했습니다.

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;
    }

}

이런 식으로 나는 SessionResponse 내부에서 세션을 조작 할 수있는 힘이 있으며, 이는 MyServicerPonseType이 여전히 세션 자체를 처리 할 수있는 것을 확장합니다.

PHP 5.4로 발표 한 PHP의 특성을 사용하여 그렇게 할 수 있습니다.

다음은 빠른 자습서입니다. http://culttt.com/2014/06/25/php-traits/

PHP는 아직 다중 클래스 상속을 지원하지 않지만 다중 인터페이스 상속을 지원합니다.

보다 http://www.hudzilla.org/php/6_17_0.php 몇 가지 예를 위해.

PHP는 여러 상속을 허용하지 않지만 여러 인터페이스를 구현할 수 있습니다. 구현이 "무거운"경우 제공하십시오 골격 구현 별도의 클래스의 각 인터페이스에 대해. 그런 다음 할 수 있습니다 모든 인터페이스 클래스를 이러한 골격 구현에 위임하십시오 ~을 통해 객체 격리.

당신이 달성하려는 것을 정확히 알지 못하면이 경우 상속이 아닌 구성을 사용하도록 응용 프로그램을 재 설계 할 가능성을 조사하는 것이 좋습니다.

항상 좋은 아이디어는 기능으로 부모 수업을 만드는 것입니다 ... 즉,이 모든 기능을 부모에게 추가하십시오.

그리고이 계층 적으로 사용하는 모든 클래스를 "이동"하십시오. 필요합니다. 기능은 구체적입니다.

기능이 공개인지 확인하려면이 주제를 참조하십시오. https://stackoverflow.com/a/4160928/2226755

그리고 많은 인수에 대해 call_user_func_array (...) 메소드를 사용하십시오.

이와 같이 :

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

프로그래밍 언어로서 PHP의 문제 중 하나는 단일 상속만을 가질 수 있다는 사실입니다. 이것은 수업이 다른 클래스에서만 상속 될 수 있음을 의미합니다.

그러나 많은 시간은 여러 클래스에서 상속하는 것이 유리할 것입니다. 예를 들어, 코드 복제를 방지하기 위해 몇 가지 다른 클래스에서 방법을 상속하는 것이 바람직 할 수 있습니다.

이 문제는 종종 상속의 가족 이력이 긴 수업으로 이어질 수 있으며, 종종 의미가 없습니다.

PHP 5.4에서 언어의 새로운 특징이 특성으로 추가되었습니다. 특성은 특성 클래스를 기존 클래스에 혼합 할 수 있다는 점에서 믹스 인과 비슷합니다. 즉, 여러 상속 문제를 피하면서 코드 복제를 줄이고 이점을 얻을 수 있습니다.

특성

클래스 A는 B {}을 연장합니다.

클래스 B는 C {}을 확장합니다.

그런 다음 A는 B와 C를 모두 확장했습니다

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top