필요한 기능을 갖춘 클래스가 여러 개 있지만 조직을 위해 별도로 저장하려는 경우 클래스를 확장하여 둘 다 가질 수 있습니까?
즉 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();
이제 논리적으로 상속 된 비즈니스 여성과 인간 모두를보십시오.
답변
<?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;
?>