2010-04-22 4 views
2

PHP 용 로그 시스템을 구현 중이며 조금 갇혀 있습니다.PHP 5의 메소드 인터셉터 *

모든 구성은 모든 메소드가 기록되도록 선언 한 XML 파일에 정의됩니다. XML은 잘 분석되어 다차원 배열 (classname => array of methods)로 변환됩니다. 여태까지는 그런대로 잘됐다.

<interceptor> 
<methods class="__CLASS_DIR__A.php"> 
     <method name="foo"> 
    <log-level>INFO</log-level> 
    <log-message>Transaction init</log-message> 
     </method> 
</methods> 
<methods class="__CLASS_DIR__B.php"> 
     <method name="far"> 
    <log-level>DEBUG</log-level> 
    <log-message>Useless</log-message> 
     </method> 
</methods> 
</interceptor> 

난 단지합니다 (XML하면 런타임에 을하고 싶은 것은 :의 나는이 구성 파일을했습니다 가정 해 봅시다 지금

#A.php 
class A { 
    public function foo($bar) { 
     echo ' // Hello there !'; 
    } 

public function bar($foo) { 
    echo " $ù$ùmezf$z !"; 
} 
} 

#B.php 
class B { 
public function far($boo) { 
    echo $boo; 
} 
} 

:

의 간단한 예를 들어 보자 파서가 일을했다) :

#Logger.php (its definitely NOT a final version) -- generated by the XML parser 
class Logger { 
public function __call($name,$args) { 
    $log_level = args[0]; 
    $args = array_slice($args,1); 
    switch($method_name) { 
     case 'foo': 
     case 'far': 
     //case ..... 
      //write in log files 
      break; 

    } 
    //THEN, RELAY THE CALL TO THE INITIAL METHOD 
} 
} 

    #"dynamic" A.php 
class A extends Logger { 
    public function foo($log_level, $bar) { 
    parent::foo($log_level, $bar); 
     echo ' // Hello there !'; 
    } 

public function bar($foo) { 
    echo " $ù$ùmezf$z !"; 
} 
} 

#"dynamic" B.php 
class B extends Logger { 
public function far($log_level, $boo) { 
    parent::far($log_level, $bar); 
    echo $boo; 
} 
} 

큰 도전은 여기에있다. XML 구문 분석기가 작업을 완료하면 A와 B를 "동적"버전으로 변환합니다.

이상적으로는 A와 B의 코드를 수정하지 않고도 (즉, 파일에서) 달성하거나 적어도 프로그램이 끝나면 원래 버전으로 돌아갈 수있는 방법을 찾아야합니다.

분명히하기 위해 PHP에서 메소드 호출을 가로채는 가장 적절한 방법을 찾고 싶습니다.

의견이 있으십니까?

추신 : 물론 클라이언트 코드에는 아무런 결과가 없어야합니다 (가로 채기를 사용하도록 설정했는지 여부는 다를 수 없음).

+0

아직 귀하의 상황을 잘 모르겠습니다. 더 자세한 내용을 추가 할 수 있습니까? 아니면 관련 코드를 보여줄 수 있습니까? 이것은 아마 다른 접근법을 사용하여 수행 되어야만하는 것처럼 들립니다. –

+0

메모 : 편집 됨 (잘하면) 명확한 – Rolf

+0

@Rolf 클래스가 이미 하위 클래스 인 경우에도 문제가 발생합니까? 이 접근법을 사용하면 parent ::를 호출하여 체인을 호출해야합니다. – Chris

답변

0

실제로 eval()을 사용하여 클래스를 실제로 정의 할 수 있지만 은 매우주의해야합니다.. eval() 기능은 매우 위험 할 수 있습니다. 이 같은

뭔가 :

$parentName = 'Bar'; 

eval('class Foo extends ' . $parentName . ' { }'); 

http://php.net/eval

+0

누군가가 eval()을 사용하지 않고 새 클래스를 정의하는 방법을 게시 할 때까지 +1하십시오. runkit은 [runkit_class_adopt()] (http://us3.php.net/manual/en/function.runkit-class-adopt.php)를 통해 상속을 동적으로 변경할 수 있습니다. –

+0

불행히도 runkit_class_adopt는 외부 라이브러리의 일부로, 앱이 호스팅 된 후 타협하여 사용합니다 ... eval과 관련하여 런타임 전에 이미 클래스가 정의되어 있으므로 모든 클래스 제목에 변수를 추가하지 마십시오. 그 구성 파일에있을 수 있습니다 ... 그냥 처음 게시물을 봐, 더 나은 방법으로 내 상황을 설명 ... – Rolf

0

이 솔루션 다시 한 번 평가 사용하지만, 나는 그것이 동적 상속의 정말 좋은 방법이라고 생각하기 때문에 나는 어쨌든 고려를 게시합니다.

여기의 방법은 변경할 수있는 기본 클래스를 확장하는 중개 클래스를 사용하는 것입니다 (이 인스턴스는 기본값을 확장하는 다른 클래스로 변경됩니다).

설정에서이 작업을 허용하지 않는 것이 무엇인지 확신 할 수 없습니다.이 설정을 명확히하면 더 나은 권장 사항을 제공 할 수 있습니다.

<?php 

/* 
* One of the following classes will be the superclass of the Child 
*/ 

class Ancestor { 
    function speak() { 
     echo 'Ancestor <br />'; 
    } 
} 

class Mum extends Ancestor { 
    function speak() { 
     parent::speak(); 
     echo 'Mum <br />'; 
    } 
} 

class Dad extends Ancestor { 
    function speak() { 
     parent::speak(); 
     echo 'Dad <br />'; 
    } 
} 

/* 
* Decide on which class we wish to make the superclass of our Child 
*/ 

$parentClass = null; 

if (isset($_GET['parent'])) { 
    $parentClass = $_GET['parent']; 
    if (!class_exists($parentClass)) { 
     $parentClass = "Ancestor"; 
    } 
} 

if (!is_null($parentClass)) { 
    eval("class ChildParent extends $parentClass {};"); 
} else { 
    class ChildParent extends Ancestor {}; 
} 

if (class_exists('ChildParent')) { 
class Child extends ChildParent 
{ 
    function speak() { 
     parent::speak(); 
     echo 'Child <br />'; 
    } 
} 
} 

/* 
* Show what's going on 
*/ 

echo '<a href="?">Either</a> | <a href="?parent=Mum">Mum</a> | <a href="?parent=Dad">Dad</a> <br />'; 

$child = new Child(); 
$child->speak();* 
+0

나는 초기 주제 (및 제목)을 업데이 트되었습니다. 전체 그림을 보려면 한 번 봐야합니다. 예제 덕분에 동적 상속 (하나의 기본 수퍼 클래스 및 XML 파서로 생성 된 클래스)에 대해 어떻게 할 것인지 이해할 수 있다고 생각합니다. – Rolf

+0

어딘가에 PHP 코드를 변경하지 않고이 작업을 수행 할 수 없습니다. 그것은 클래스 구조에 있거나 객체 자체의 인스턴스화 중 하나입니다. 위의 첫 번째 방법. 두번째 방법은'new MyClass();'대신'Neu :: MyClass();'를 사용합니다. 그래서 어떤가? – icio

+0

또는 런킷 (runkit). – icio