2010-06-20 2 views
2

나는이 문제를 해결하는 데 어려움을 겪고 있습니다. 나는 너희 모두가 나를 도울 수 있기를 바라고있다. PHP에서 이미 초기화 된 부모를 자식으로 확장 시키십시오.

베스트 예를 들어 설명 :

class Parent { 
    public $nationality; 

    function __construct($nationality) 
    { 
     $this->nationality = $nationality 
    } 
} 

class Child extends Parent { 
    function __construct() { 
     echo $this->nationality; // hispanic 
    } 
} 

// Usage: 
$parent = new Parent('hispanic'); 
$child = new Child(); 

나는 아이가 이미 초기화 된 부모로부터 속성과 메서드를 상속합니다.


편집 : 답장을 보내 주셔서 감사합니다. 배경을 알려주세요. 저는 템플릿 시스템을 만들려고합니다. Tag.php와 Form.php라는 두 클래스가 있습니다.

I는 다음과 같이 그것을 싶습니다

나는 복합 패턴을 좋아하지 않는 이유는 그것이 내가 인스턴스를 전달 할 왜 나에게 이해가되지 않는다는 것입니다
class Tag { 
    public $class_location; 
    public $other_tag_specific_info; 
    public $args; 

    function __construct($args) 
    { 
     $this->args = $args; 
    } 

    public function wrap($wrapper) { 
     ... 
    } 

    // More public methods Form can use. 
} 

class Form extends Tag { 
    function __construct() { 
     print_r($this->args()) // 0 => 'wahoo', 1 => 'ok' 
     echo $this->class_location; // "/library/form/form.php" 
     $this->wrap('form'); 
    } 

    function __tostring() { 
     return '<input type = "text" />'; 
    } 
} 

// Usage: 
$tag = new Tag(array('wahoo', 'ok')); 
$tag->class_location = "/library/form/form.php"; 
$tag->other_tag_specific_info = "..."; 
$form = new Form(); 

태그의 생성자에 하위 클래스 중 하나 인 afterall - Form이 Tag 유형의 권리입니까?

감사합니다. Matt Mueller

+0

저는 PHP가 계층 적 객체 캐스팅 (위/아래 캐스팅)을 수행하지 않으므로 이것이 가능하지 않다고 생각합니다. – BoltClock

+1

'자식 '과'부모 '란 무엇입니까? 이런 식으로 모델링하는 것이 맞습니까? 일반적으로 상속을 사용하여 특정 클래스를보다 구체적으로 만들거나 기능을 그룹화합니다. '오리'와 마찬가지로 '새'는 '동물'입니다. 당신의 모범이 잘 선택되지 않은 것 같습니다. 이 경우, 두 객체 모두'Person' 클래스의 객체이고'parent' 속성을 가져야합니다. –

+0

좋은 지적. 약간의 정보를 추가해 설명해 보겠습니다. – Matt

답변

3

우리는 여기서 이미 꽤 많은 부분을 편집 했으므로 나는 단지 새로운 대답을 게시 할 것입니다. 그것을 위해 내 오래된 대답을 남겨 둘 것입니다.

어쨌든, 최근 예제 (Form extends Tag)부터 시작하겠습니다.또한

class TagBuilder 
{ 
    protected $args; 

    protected $className; 

    protected $classLocation; 

    function __construct() 
    { 

    } 

    public function setClass($file, $class) 
    { 
     /* @todo Use reflection maybe to determine if $class is a Tag subclass */ 

     if (file_exists($file)) 
     { 
      require_once $file; // Or use the autoloader 
     } 

     $this->classLocation = $file; 
     $this->className = $class; 
    } 

    /** 
    * @return Tag the built tag (or tag subclass) instance 
    */ 
    public function getTag() 
    { 
     $fullyQualifiedClassName = $this->getFullyQualifiedClassName(); 

     $newTag = new $fullyQualifiedClassName($this->args); 
     $newTag->class_location = $this->classLocation; 

     return $newTag; 
    } 

    protected function getFullyQualifiedClassName() 
    { 
     return $this->className; 
    } 

    public function setArgs($args) 
    { 
     $this->args = $args; 
    } 
} 

, 당신이 parent::__construct($args)있어 호출 할 양식 생성자를 수정해야합니다 : 당신이 Builder pattern의 어떤 모방, 그래서 나와 함께 곰과의 짧은 예를 갈 수 있도록 노력하고 같은

보인다 메서드를 호출하여 $args 종속성을 전달합니다. 다음

그리고

$builder = new TagBuilder(); 
$builder->setClass('/library/form/form.php', 'Form'); 
$builder->setArgs(array('wahoo', 'ok')); 

$form = $builder->getTag(); 

이 그것을 실행 긴 예를 약간이며 영업 이익의 API의 일부를 변경하는 것을 의미하지만, 내가 제대로 질문을 이해한다면, 다음이 원하는 동작 (또는 부분적으로) OP는 자신의 응용 프로그램에서 모방하고 싶어합니다.


참고 : 내가이 빌더 패턴의 고전적인 예 아니라는 것을 알고와 getTag 방법은 일부 지지자에 약간 모호한 보일 수도있다.

+0

자세한 답변을 보내 주셔서 감사합니다. 불행히도 작동하지 않습니다. Form은 Tag 또는 TagBuilder를 확장합니까? 나는 이것이 Form보다 먼저 Tag (builder)를 인스턴스화하는 문제를 해결할 수 있다고 믿지만, Form의 생성자에서'echo $ this-> class_location'을 푸는 것은 아니다. – Matt

+0

'$ this-> class_location'으로, Tag 또는 TagBuilder에서 설정됩니다. – Matt

+1

양식 클래스는 예제와 동일합니다. 전체 아이디어는 상속 할 태그를 들고 다니는 대신 빌더를 작성하고 빌더가 구성되는 방법에 관한 정보를 전달하지 않고도 어디서나 빌더를 전달하는 것입니다. 나는 당신의 의도를 오해했을지도 모른다. 나는 그 대답을 제거 할 수있다. –

7

틀린 것은 틀림없이 나쁜 디자인입니다. 다른 국적의 여러 Parent 인스턴스를 만든 다음 새 Child 인스턴스를 만드는 경우 어떻게됩니까? 이 어린이는 다음 중 어떤 국적을 갖습니까?

왜 Child 클래스를 합성 클래스로 만들지 말고, 생성자에 부모 클래스를 지정해야합니다.

class Child 
{ 
    private $parent; 

    function __construct($parent) 
    { 
     $this->parent = $parent; 
    } 

    function getNationality() 
    { 
     return $this->parent->nationality; 
    } 
} 

다음은

$parent = new Parent('hispanic'); 
$child = new Child($parent); 

으로 또는 부모로부터 공장 방법을 만들 ... 나머지는 당신의 상상력에 달려있다.


참고 : 나는 사실을 무시하고의 I 부모 클래스의 국적에 대한 게터를 사용하지 않았고 내가 아이를위한 슈퍼 클래스를 제공 않았다 (? 어쩌면 부모 정말 이해가되지 않습니다). 이러한 것들은 모두 설계 관련 사항이지만이 질문의 맥락에 속하지 않습니다.

+0

응답 해 주셔서 감사합니다. 전에도 이런 일을 했었지만 실제로는 제 특정 응용 프로그램에서 저와 잘 어울리지 않았습니다. 다른 해결책이 있기를 바랍니다. 감사! – Matt

+1

새 인스턴스를 만드는 것이 문제가됩니까? 아마도 당신이 변경할 수없는 일종의 레거시 API를 사용하고 있습니까? 왜 그런 "계층 구조"를 만들고 싶은지에 대한 배경을 우리에게 주면 도움이 될 것입니다. –

+0

아 좋아. 내 방법이 나쁜 습관으로 간주되는 이유를 설명해 주셔서 감사합니다. 내 경우에는 효과가 있지만 나는 이것을해야한다고 생각하지 않습니다. 내 사건에 대해 약간의 배경 지식을 추가했습니다. – Matt

0

이것은 좋은 습관이라고 생각해서는 안되며, 나는 그것이 완료 될 수 있는지 여부를 확인하기위한 개념 증명으로 기능을 작성했습니다.

그것은 정확하게 당신이 원하는 것을하지 않는

... 그것은 부모 클래스의 인스턴스를 받아 자식 클래스의 인스턴스로 변경하지만 아마 새 자식 동안을 만들 수정할 수

class MyClass 
{ 
    public $_initial = NULL; 

    public function setInitial($value) { 
     $this->_initial = $value; 
    } 

} 


class MyClass2 extends MyClass 
{ 
    private $_reversed = NULL; 

    private function reverseInitial() { 
     $this->_reversed = strrev($this->_initial); 
    } 

    public function getReversed() { 
     $this->reverseInitial(); 
     return $this->_reversed; 
    } 

} 


$class1 = new MyClass(); 
$class1->setInitial('rekaB kraM'); 

inherit($class1,'MyClass','MyClass2'); 

echo $class1->getReversed(); 

function inherit(&$object, $oldClassName, $newClassName) { 
    $oldClass = new ReflectionClass($oldClassName); 
    $newClass = new ReflectionClass($newClassName); 

    $wrkSpace = serialize($object); 
    $wrkTmp = explode('{',$wrkSpace); 
    $startBlock = array_shift($wrkTmp); 

    $oldClassProperties = $oldClass->getProperties(); 
    $oldClassPropertyNames = array(); 
    foreach($oldClassProperties as $oldClassProperty) { 
     if (!$oldClassProperty->isStatic()) { 
      if ($oldClassProperty->isPrivate()) { 
       $oldClassPropertyNames[] = "\x0".$oldClassName."\x0".$oldClassProperty->getName(); 
      } elseif($oldClassProperty->isProtected()) { 
       $oldClassPropertyNames[] = "\x0*\x0".$oldClassProperty->getName(); 
      } else { 
       $oldClassPropertyNames[] = $oldClassProperty->getName(); 
      } 
     } 
    } 

    $newClassProperties = $newClass->getProperties(); 
    $newClassPropertyValues = $newClass->getDefaultProperties(); 

    $newClassPropertyNames = array(); 
    foreach($newClassProperties as $newClassProperty) { 
     $propertyName = $newClassProperty->getName(); 
     if (!$newClassProperty->isStatic()) { 
      if ($newClassProperty->isPrivate()) { 
       $newPropertyName = "\x0".$newClassName."\x0".$propertyName; 
      } elseif($newClassProperty->isProtected()) { 
       $newPropertyName = "\x0*\x0".$propertyName; 
      } else { 
       $newPropertyName = $propertyName; 
      } 
      $newClassPropertyNames[] = $newPropertyName; 

      if (isset($newClassPropertyValues[$propertyName])) { 
       $newClassPropertyValues[$newPropertyName] = $newClassPropertyValues[$propertyName]; 
      } 
     } 
    } 


    $newClassPropertySet = array_diff($newClassPropertyNames,$oldClassPropertyNames); 

    $toClassName = 'O:'.strlen($newClassName).':"'.$newClassName.'":'.(count($newClassPropertySet)+count($oldClassPropertyNames)).':'; 

    $newPropertyEntries = array_fill_keys($newClassPropertySet,NULL); 
    foreach($newPropertyEntries as $newPropertyName => $newClassProperty) { 
     if (isset($newClassPropertyValues[$newPropertyName])) { 
      $newPropertyEntries[$newPropertyName] = $newClassPropertyValues[$newPropertyName]; 
     } 
    } 
    $newPropertyEntries = substr(serialize($newPropertyEntries),4+strlen(count($newClassPropertySet)),-1); 

    $newSerialized = $toClassName.'{'.$newPropertyEntries.implode('{',$wrkTmp); 

    $object = unserialize($newSerialized); 
} 
부모는 그대로 둔다.

+0

hehe, 재미있는 것들. 학문적 우수성을위한 포인트. 그래도 집에서 이것을 시도하지 말아라;) – Kris

+2

나는 프로덕션 코드에서 결코 그것을 사용하지 않을 것이다. 그러나 요즘 나는이 아이디어에 관심을 갖게 될 것이고 disinherit() 함수도 쓸 것이다. –

+0

나는 그것이 킥킥 웃게 만들었 기 때문에 이것을 업 그레 이드했을 것이다.하지만 나는 너무 겁에 질려 움직이는 사람들이 실제로 이런 종류의 일을하도록 머리를 맞을 수도있다. – Kris

0

좋아요, 다른 사람들은 이것이 나쁜 디자인 아이디어라고 말합니다. 나는 반쯤 반대하고 클래스 기반의 OO 계층 구조가 당신이 원하는 모든 호의를 수행하지 못하는 문제 영역을 뛰어 넘을 가능성이 있음을 알려줄 것입니다. 이 아이디어에 대해 궁금하다면 Steve Yegge의 "The Universal Design Pattern"(http://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html)을 읽는 것이 좋습니다.

그러나 그는 조금 장황한, 그래서이 짧 수 있습니다 자바 스크립트에서 그 생각만으로도 흥미, 여기에 무슨 말을하는지하는 것은 사소한 것 :

이유이의
t = new Tag({arg1: val1, arg2: val2}) 
// ... 
// later, when you decide t is a Form 
t.prototype = Form.prototype. 

많은 자바 스크립트를 사용하는 작업은 프로토 타입 기반 OO와 관련이 있지만, 함수가 변수에 할당되고 전달 될 수있는 최상위 클래스 값이라는 사실 또한 많이 있습니다. PHP는 함수를 동적으로 호출 할 수있는 몇 가지 기능을 제공합니다 (5.3을 사용하면 함수를 할당/전달할 수 있습니다). 제 생각에 당신이 관심이 있고 언어의 수업 기반 시설 밖에서 나설 의사가 있다면 아마도 이렇게 많은 것을 할 수있을 것입니다.

먼저, 클래스가없는 언어로 객체 지향 코드를 작성하는 사람들은 "클래스"가 해시/연관 배열 (AAs) 일 수 있습니다.

$quasiObj = array('prop1' => $val1, 'prop2' => $val2, '_class' => 'quasiClass'); 

사용자의 메서드는 AA 참조를 첫 번째 인수로 사용하는 함수 일 수 있습니다.

function quasiClass_method1Name($this,$args = array()) { 
    $this['prop1'] = $args[1] * $args[2]; 
} 

당신은 클래스 독립적 인 메소드 호출을 원하는 경우에, 당신은 래퍼 기능을 할 수 있습니다 :이 시스템에서

function method($this,$methodName,$args) { 
    $fullMethodName = "{$this['_class']}_$methodName"; 
    $fullMethodName($this,$args); 
} 

// and now, the invocation 
method($quasiObj,'method1Name',array(6,7)); 

, 당신은 Form-Tag에서 $quasiObject을 홍보하려는, 그것은이다 배열의 _class 키를 변경하는 간단한 문제. 내부 상태 변경이 필요한 경우 함수/메소드를 작성하여 처리 할 수 ​​있습니다.

당신은 통역사를 잃어 버리고 당신을 위해 일을 추적하고, 어떤 사람들은 그 일을 정말로 극복합니다. PHP를 너무 빨리 사용하고 느슨하게하기 때문에 대부분의 사람들은 자바를 사용합니다. 그것은 역동적 인 언어입니다. 그 사실을 이용하십시오.:)

+0

그가 태그 위임자/프록시를 소유하고있는 복합체 인 Form을 사용하여이 작업을 수행 할 수없는 이유는 없습니다. –

+0

* shrug *. 물론, Asker는 그것이 옵션이라는 것을 깨달았습니다. 나는 그가 명백한 간접비 때문에 어쨌든 물었다고 생각합니다. 클래스 스위치에 많은 내부 상태 변경 사항이있는 경우에는 그만한 가치가 있습니다. 마찬가지로 클래스 독립적 인 메서드 호출이 많이있는 경우에도 마찬가지입니다 (제안 된 시스템에서 다소 비쌉니다).그것 이외에, 그것은 실제로 심미적 인 호명이며, 이것은 복합 패턴을 사용하기보다는 이것을 피할 수 있음을 지적하는 것처럼 보입니다. 그래도 디자인 패턴을 선호한다면, 자신을 노크 할 수 있습니다. –

관련 문제