source

PHP에서 여러 클래스를 사용하여 클래스를 확장할 수 있습니까?

gigabyte 2022. 12. 28. 21:36
반응형

PHP에서 여러 클래스를 사용하여 클래스를 확장할 수 있습니까?

필요한 기능을 가진 클래스가 여러 개 있지만 조직용으로 따로 저장하려는 경우 클래스를 확장하여 둘 다 가질 수 있습니까?

ㅇㅇㅇ.class a extends b extends c

를 한 번에 하나씩 을 알고 을 찾고 .- 에서는 할, 에 하지 않는 입니다. 수 있습니다.class c extends b,class b extends a

PHP 5.3에서 여러 상속을 가짜로 만들고 싶다면 __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, Squak, 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에 대해 '알고' 있습니다.이 관계를 설정하려면 OtherClass에 "setExtendee"라는 공용 함수가 있어야 합니다.그 후 $foo에서 메서드를 호출하면 내부적으로 $foo에 액세스할 수 있습니다.그러나 실제 확장 클래스와 달리 개인/보호 메서드/변수에 액세스할 수 없습니다.

특성을 기본 클래스로 사용합니다.그런 다음 부모 클래스에서 사용합니다.확장합니다.

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

비즈니스와 인간 모두를 논리적으로 계승한 비즈니스 우먼을 만나보세요.

편집: 2020 PHP 5.4+ 및 7+

PHP 5.4.0에서는 "Trits"가 있습니다.한 클래스에서 더 많은 특성을 사용할 수 있습니다.따라서 최종 결정 포인트는 상속을 정말 원하는지 아니면 그저 "기능"이 필요한지가 될 것입니다.특성은, 애매하게 말하면, 이미 실장되어 있는 인터페이스이며, 그 목적은used.


Currently accepted answer by @Franck will work but it is not in fact multiple inheritance but a child instance of class defined out of scope, also there is the `__call()` shorthand - consider using just `$this->childInstance->method(args)` anywhere you need ExternalClass class method in "extended" class.

정확한 답변

아니요, 키워드 매뉴얼에 기재되어 있는 와 같이 각각은 할 수 없습니다.

확장 클래스는 항상 단일 기본 클래스에 종속됩니다. 즉, 다중 상속은 지원되지 않습니다.

정답

그러나 @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 
<?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 인터페이스를 프로그래밍하는 것을 권장하는 기사를 몇 개 읽었습니다.
를를를를를를를를를를를를를를를를를 。클래스 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 Mailer 소스 코드, 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을 확장한 SessionResponse 내에서 세션을 조작할 수 있습니다.이것에 의해, 세션은 아직 혼자서 처리할 수 있습니다.

함수의 공개 여부를 확인하려면 다음 항목을 참조하십시오.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 5.4에서 발표된 PHP의 특성을 사용하여 이를 수행할 수 있습니다.

여기 간단한 튜토리얼이 있습니다.http://culttt.com/2014/06/25/php-traits/

프로그래밍 언어로서의 PHP의 문제점 중 하나는 단일 상속만 할 수 있다는 것입니다.즉, 클래스는 다른 클래스에서만 상속할 수 있습니다.

하지만, 많은 경우 여러 계층에서 물려받는 것이 유익할 것이다.예를 들어 코드 중복을 방지하기 위해 몇 가지 다른 클래스에서 메서드를 상속하는 것이 바람직할 수 있습니다.

이 문제는 종종 이치에 맞지 않는 유산의 오랜 가족력을 가진 계층으로 이어질 수 있다.

PHP 5.4에서는 Features로 알려진 언어의 새로운 기능이 추가되었습니다.특성 클래스는 기존 클래스로 혼합할 수 있다는 점에서 믹신과 비슷합니다.즉, 코드 중복을 줄이고 여러 상속 문제를 방지하면서 이점을 얻을 수 있습니다.

특성들

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

예에 대해서는, http://www.hudzilla.org/php/6_17_0.php 를 참조해 주세요.

PHP는 다중 상속을 허용하지 않지만 여러 인터페이스를 구현할 수 있습니다.실장이 「중요」한 경우는, 다른 클래스의 각 인터페이스에 골격의 실장을 실시합니다.그런 다음 객체 억제를 통해 모든 인터페이스 클래스를 이러한 골격 구현에 위임할 수 있습니다.

무엇을 달성하려고 하는지 정확히 알지 못하기 때문에, 이 경우 상속이 아닌 구성을 사용하도록 애플리케이션을 재설계하는 것을 제안합니다.

항상 좋은 생각은 부모 클래스를 만들고, 함수가 있는... 즉, 이 모든 기능을 부모 클래스에 추가하는 것입니다.

계층적으로 이를 사용하는 모든 클래스를 아래로 "이동"합니다.특정 함수를 다시 작성해야 합니다.

2022년에는 클래스 기능을 에뮬레이트해, 그것을 성장시켜 「실현」할도 있습니다.

이 코드는 php 8.2 베타 3에서 성공적으로 테스트되고 있습니다.

<?php

$_=(object)($class=[
    'extend'=>function($propname,$obj){
        $GLOBALS['class'][$propname]=$obj;
        $GLOBALS['_']=(object)$GLOBALS['class'];
    }
]);




($_->extend)('trickyextend',function(){echo 'hi there!';});
($_->trickyextend)();


($_->extend)('whatwhowhere',function($msg){echo $msg;});
($_->whatwhowhere)('this is php!');

?>

정답이 아닙니다. 중복 클래스가 있습니다.

...하지만 효과가 있습니다:)

class A {
    //do some things
}

class B {
    //do some things
}

class copy_B는 모든 클래스 B를 복사합니다.

class copy_B extends A {

    //do some things (copy class B)
}

class A_B extends copy_B{}

지금이다

class C_A extends A{}
class C_B extends B{}
class C_A_b extends A_B{}  //extends A & B

클래스 A는 B {}를 확장합니다.

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

그러면 A는 B와 C를 모두 확장했습니다.

언급URL : https://stackoverflow.com/questions/356128/can-i-extend-a-class-using-more-than-1-class-in-php

반응형