2012-11-13 4 views
3
더 정확하게 문제

전화 자식 clases '__call 방법이 존재하고, 예외를 던져하지 않을 경우

내가 해결하기 위해 노력하고 문제를 반영하기 위해 제목을 업데이트 [편집]이있다

: 내가 알 필요가 메서드가 parent::을 통해 호출되었고 debug_backtrace을 사용할 수있는 동안이 작업을 수행하는 더 좋은 방법이있는 것처럼 보입니다.

나는 정적 인 바인딩을 조사하고 있었지만 해결책을 짐작할만큼 충분히 이해하지 못했습니다.

문제의 방법은 __call입니다. 따라서 더 정확하게 또는 덜 정확하게 두 가지 오류가있는 추가 매개 변수를 전달할 수 없습니다.

이 문제를 해결하려는 이유는 부모 클래스가 __call이지만 자식은 _call 일 수도 있고 아닐 수도 있습니다. 자식이 가지고 있지 않고 부모가 호출을 전달하지 않으면 예외 또는 오류가 발생합니다. 아이가 그 방법을 가지고 있다면, 우리는 false (우리가 이것을 처리하지 않았다)을 돌려 줄 것이고 자식 _call 방법을 계속하도록 할 것이다.

지금까지 유일한 해결책은 자식이 parent::__call을 try/catch 블록으로 싸인하고 부모가 요청을 라우트하지 않는 경우 기본적으로 예외를 throw하도록하는 것입니다.

즉.

class Parent { 
    public function __call($method, $params) { 
    if(preg_match($this->valid, $method) { 
     $this->do_stuff(); 
     // if child has a call method, it would skip on true 
     return true; 
    } 
    elseif(** CHILD HAS CALL METHOD **) { 
     // this would let the child's _call method kick in 
     return false; 
    } 
    else { 
     throw new MethodDoesNotExistException($method); 
    } 
    } 
} 

class Child extends Parent { 
    public function __call($method, $params) { 
    if(! parent::__call($method, $params)) { 
     do_stuff_here(); 
    } 
    } 
} 

방법을 처리하지 않는 부모가 그냥 아주 잘하지 않는 것 흐름 설정 제어에 대한 예외를 사용하는 등, 더 우아한 해결책이 있는지 확인 시도하고, 작동하는 경우에 예외를 던지는 동안. 하지만 스택 트레이스를 사용하여 호출자를 파악하는 것도 마찬가지입니다.

+0

을했다 당신은 무엇을 할 때 이해하지 못했다 후기 바인딩 사용? – arkascha

답변

4

이것은 당신의 부모 클래스에서 수행해야합니다

if (__CLASS__ != get_class($this)) 
+0

이것은 자식 클래스의 이름과 부모 클래스의 이름을 알려주지 만 자식'_call' 메서드가 있는지 결정할 수는 없습니다 – Will

+0

이것은 원하는 것을 얻을 수 있지만 OP로 제안합니다 자녀 클래스에 대한 지식을 부모 클래스에 추가하는 것은 나쁜 설계 방법입니다. –

+0

@Will 글쎄, 그것은 제목에서 질문에 대답. 자식 클래스는 부모로부터 상속하기 때문에 항상'__call' 메쏘드를 가질 것입니다. 당신은 당신의 자식 클래스가 자신의'__call' 메쏘드를 가지고 있는지를 알아 내기 위해 많은 내성 검사를해야 할 것입니다. 이것은 응용 프로그램 구조가 좋지 않은 것 같습니다. 부모는 자녀를 전혀 인식하지 않아야합니다. 아이는 적절한 경우 부모를 오버라이드합니다. – deceze

1

나는이 귀하의 요구에 맞는 나는 또한 해킹 이런 종류의 뷰의 객체 지향 설계 점에서 정말 나쁜 생각하면 완전히 확실하지 않다.

$c = new ChildClass1(); 
$c->one(); 
$c->foo(); 

$c = new ChildClass2(); 
$c->foo(); 

은 얻을 것이다 : 그러나, 그것은 :)

<?php 

class ParentClass 
    { 
    public function __call($method, $params) 
    { 
    if($method === 'one') 
    { 
     echo "Parent\n"; 
     return true; 
    } 
    elseif($this->shouldForwardToSubclass($method)) 
     { 
     return false; 
     } 
    else 
    { 
     throw new Exception("No method"); 
    } 
    } 

    protected function shouldForwardToSubclass($methodName) 
    { 
     $myClass = get_class($this); 
     if (__CLASS__ != $myClass) 
     { 
     $classObject = new ReflectionClass($myClass); 
     $methodObject = $classObject->getMethod('__call'); 
     $declaringClassName = $methodObject->getDeclaringClass()->getName(); 
     return $myClass == $declaringClassName; 
     } 
     else 
      { 
      return false; 
      } 
} 

} 

class ChildClass1 extends ParentClass { 
    public function __call($method, $params) { 
    if(! parent::__call($method, $params)) 
    { 
     echo "Child handle!\n"; 
    } 
    } 
} 

class ChildClass2 extends ParentClass { 
} 
나중에

일을 코드에 재미있는 일이라고

Parent 
Child handle! 
PHP Fatal error: Uncaught exception 'Exception' with message 'No method' in /home/andres/workspace/Playground/test.php:18 
Stack trace: 
#0 /home/andres/workspace/Playground/test.php(58): ParentClass->__call('foo', Array) 
#1 /home/andres/workspace/Playground/test.php(58): ChildClass2->foo() 
#2 {main} 

HTH를