필요한 기능을 갖춘 클래스가 여러 개 있지만 조직을 위해 별도로 저장하려는 경우 클래스를 확장하여 둘 다 가질 수 있습니까?
즉 class a extends b extends c
편집 : 클래스를 한 번에 하나씩 확장하는 방법을 알고 있지만 여러 기본 클래스를 사용하여 클래스를 즉시 확장하는 방법을 찾고 있습니다. class c extends b
,class b extends a
필요한 기능을 갖춘 클래스가 여러 개 있지만 조직을 위해 별도로 저장하려는 경우 클래스를 확장하여 둘 다 가질 수 있습니까?
즉 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 디자인과 같으며 많은 언어가 다중 상속을 허용하지 않는 이유와 같습니다. 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();
이제 논리적으로 상속 된 비즈니스 여성과 인간 모두를보십시오.
BusinessWoman
대신에 특성을 사용하지 BusinessPerson
않습니까? 그런 다음 실제 다중 상속을 가질 수 있습니다.
<?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;
?>
@Franck에 의해 현재 받아 들여진 대답은 효과가 있지만 실제로 다중 상속은 아니지만 범위를 벗어난 클래스의 자식 인스턴스입니다. 또한 __call()
속기 가 $this->childInstance->method(args)
있습니다. "확장 된"클래스에서 ExternalClass 클래스 메서드가 필요한 곳 어디에서나 사용하십시오 .
키워드 매뉴얼에extends
따르면 실제로는 그렇지 않습니다 .
확장 클래스는 항상 단일 기본 클래스에 의존합니다. 즉 다중 상속은 지원되지 않습니다.
그러나 @adam이 올바르게 제안한 것처럼 다중 계층 상속을 사용하는 것은 금지되지 않습니다.
한 클래스를 다른 클래스와 다른 클래스로 확장 할 수 있습니다.
이에 대한 간단한 예는 다음과 같습니다.
class firstInheritance{}
class secondInheritance extends firstInheritance{}
class someFinalClass extends secondInheritance{}
//...and so on...
알다시피 , 프로세스에 포함 된 모든 클래스를 제어 할 수있는 경우 계층 구조로만 여러 (2+) intehritance 만 수행 할 수 있습니다. 즉, 내장 클래스 또는 클래스를 사용하여이 솔루션을 적용 할 수 없습니다. 단순히 편집 할 수 없습니다-그렇게하고 싶다면 @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
(라이브러리 / 프레임 워크와 달리) 프로젝트의 상속을 권장하지 않으며 구현에 대한 것이 아니라 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;
}
}
이 방법으로 SessionResponse 내에서 세션을 조작하여 MyServiceResponsetype을 확장하여 세션을 자체적으로 처리 할 수 있습니다.
함수가 공개인지 확인하려면 다음 주제를 참조하십시오. 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의 Traits를 사용하여이를 수행 할 수 있습니다.
다음은 간단한 자습서입니다. http://culttt.com/2014/06/25/php-traits/
PHP는 아직 다중 클래스 상속을 지원하지 않지만 다중 인터페이스 상속을 지원합니다.
몇 가지 예는 http://www.hudzilla.org/php/6_17_0.php 를 참조 하십시오 .
항상 좋은 생각은 함수를 사용하여 부모 클래스를 만드는 것입니다. 즉,이 모든 기능을 부모에게 추가하십시오.
그리고 이것을 계층 적으로 사용하는 모든 클래스를 "이동"하십시오. 필자는 특정 기능을 다시 작성해야합니다.
프로그래밍 언어로서 PHP의 문제점 중 하나는 단일 상속 만 가질 수 있다는 사실입니다. 이것은 클래스가 다른 클래스에서만 상속 할 수 있음을 의미합니다.
그러나 많은 시간을 여러 클래스에서 상속하는 것이 좋습니다. 예를 들어, 코드 복제를 방지하기 위해 두 개의 다른 클래스에서 메소드를 상속하는 것이 바람직 할 수 있습니다.
이 문제는 가족의 상속 상속 역사가 긴 수업으로 이어질 수 있습니다.
PHP 5.4에서는 언어의 새로운 기능이 속성으로 추가되었습니다. 특성은 특성 클래스를 기존 클래스에 혼합 할 수 있다는 점에서 믹스 인과 유사합니다. 즉, 다중 상속 문제를 피하면서 코드 중복을 줄이고 이점을 얻을 수 있습니다.
이것은 실제 답변이 아닙니다. 중복 수업이 있습니다.
...하지만 작동합니다 :)
class A {
//do some things
}
class B {
//do some things
}
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