2010-05-28 6 views
8

PHP 리플렉션 메서드를 살펴 봤는데, 내가 원하는 것은 메서드를 연 다음 임의의 반환 값 앞에 일부 코드를 삽입하는 것입니다. 예를 들어 변경하려면 :런타임시 메서드/함수 수정

function foo($bar) 
{ 
    $foo = $bar ; 
    return $foo ; 
} 

그리고 주입 그것에 몇 가지 코드가 같은 :

function foo($bar) 
{ 
    //some code here 
    $foo = $bar ; 
    //some code here 
    return $foo ; 
} 

가능?

+0

나는 당신이 원하는 것이 가능하다고 생각하지 않습니다. 나는 틀릴 수도 있지만 일반적으로 * Reflection API *는 ** 클래스에 대한 정보를 ** 얻고 런타임에 코드를 변경하지 않는 데 사용됩니다. –

+0

개봉하려고하는 것에 대해 더 많은 정보를 제공하고 다른 해결책을 찾을 수 있도록 도울 수 있습니다. – Galen

+0

이것이 해결책이 될 것이며 필요한 것이 무엇인지 알고있을 것입니다. 런타임 중에 함수의 본질을 변경하려는 이유는 무엇입니까? 더 나은 옵션은 함수 흐름을 제어하는 ​​변수를 전달하는 것입니다. 또는 eval() 문을 사용하여 코드를 실행하는 방법을 고려해보십시오. 이런 식으로 생각하십시오 : 미리 결정 가능한 효과가없는 함수의 이름을 무엇입니까? – Kurucu

답변

2

anonymous functions으로 조사하십시오. PHP 5.3을 실행할 수 있다면 당신이하려는 일에 더 가까울 수 있습니다.

2

적어도, 내가하는 방식대로는 불가능합니다. 주석이 제안했듯이, 리플렉션은 클래스/함수에 대한 정보를 얻기위한 것이지 수정하는 것이 아닙니다.

Runkit이라는 PHP 확장이 있습니다.이 유형의 기능은 - http://www.php.net/manual/en/book.runkit.php을 제공하지만, 대다수의 호스트에 기본적으로 설치되지는 않습니다.

그래도 다른 방법이있을 수 있습니다. 아마도 당신이하려는 일에 대해 더 많은 정보를 줄 수 있고, 문제의 기능을 수정할 수없는 이유가 있다면, 우리는 몇 가지 지침을 제공 할 수있을 것입니다. 예 : 핵심 PHP 함수를 수정하려는 함수 또는 편집하고 싶지 않은 타사 라이브러리의 코드입니까?

+0

runkit은이 주석을 게시 할 때 베타입니다. 컴파일하지 않습니다 (PHP 5.3.19를 사용하여 Linux에서 컴파일 할 때 오류가 발생합니다). – NickSoft

0

그냥 아이디어 :

function foo($bar, $preprocess, $postprocess){ 

    //IF CONDITION($preprocess) 
    include('/mylogic/'.$preprocess.".php"); //do some preprocessing here? 
    $foo = $bar ; 
    //IF CONDITION($postprocess) 
    include('/mylogic/'.$postprocess.".php"); //process $foo here? 
    //FINALLY return 
    return $foo; 

} 
+0

좋은 생각 ... 아마도 $ preprocess와 $ postprocess를 콜백 ('functionname'또는 array ('classname', 'methodname'))으로 만들고 call_user_func를 사용하여 호출 할 수 있습니다. 그것은 범위를 좁히는 함의를 가지고있을 것이지만, 그것은 또한 더 안전한 IMHO가 될 것입니다. – grossvogel

+0

내 응용 프로그램의 모든 메서드에 대해 수행해야하며 깨끗하게 유지해야합니다. – mononym

4

음, 한 가지 방법, 모든 방법을하는 것은 "가상"호출

class Foo { 
    protected $overrides = array(); 

    public function __call($func, $args) { 
     $func = strtolower($func); 
     if (isset($this->overrides[$func])) { 
      // We have a override for this method, call it instead! 
      array_unshift($args, $this); //Add the object to the argument list as the first 
      return call_user_func_array($this->overrides[$func], $args); 
     } elseif (is_callable(array($this, '_' . $func))) { 
      // Call an "internal" version 
      return call_user_func_array(array($this, '_' . $func), $args); 
     } else { 
      throw new BadMethodCallException('Method '.$func.' Does Not Exist'); 
     } 
    } 

    public function addOverride($name, $callback) { 
     $this->overrides[strtolower($name)] = $callback; 
    } 

    public function _doSomething($foo) { 
     echo "Foo: ". $foo; 
    } 
} 

$foo = new Foo(); 

$foo->doSomething('test'); // Foo: test 

PHP 5.2 :

$f = create_function('$obj, $str', 'echo "Bar: " . $obj->_doSomething($str) . " Baz";'); 

PHP 5.3 :

$f = function($obj, $str) { 
    echo "Bar: " . $obj->_doSomething($str) . " Baz"; 
} 
,210

모든 PHP는 :

$foo->addOverride('doSomething', $f); 

$foo->doSomething('test'); // Bar: Foo: test Baz 

그것은 "오버라이드"에 대한 첫 번째 방법으로 개체의 인스턴스를 전달합니다. 참고 :이 "재정의"메서드는 클래스의 보호 된 멤버에 액세스 할 수 없습니다. 따라서 게터 (__get, __set)를 사용하십시오. 실제 호출이 __call()에서 오는한지 ...,

주를 보호 방법에 액세스 할 수 있습니다 : 당신은이 작업을 위해 '_'로 시작되는 모든 기본 방법을 수정해야합니다. .. (또는 다른 접두사 옵션을 선택할 수도 있고 모두 보호 할 수 있습니다.) ...

-1

어쩌면 제가 누락되었지만 실제로 말하는 것처럼 코드를 삽입하고 싶습니까? 무엇을 성취하려고합니까? A가 발생했을 때 한 블록의 코드를 실행하고 B가 발생하면 다른 한 블록 만 실행하려면 if() 문과 같은 간단한 프로그래밍 논리 만 있으면됩니다.

런타임에 함수를 변경하려고하십니까? 아니면 그냥 논리 문제입니까?

수행해야 할 작업에 대해 자세히 설명하십시오.

0

원래 오토로더 앞에 특수한 오토로더를 추가하고 원본 자동로드가로드 할 파일을 읽고 내용을 변경하고 다른 곳 (예 : 일부 tmp 디렉토리)에 저장하고 원래 파일 대신 수정 된 파일을 포함시킬 수 있습니다 하나.

0

똑같은 일을하고 싶었 기 때문에, 계측 할 클래스로 호출 할 @ircmaxell 기법을 계측하고 활용하려고했던 클래스를 대체 할 일반 계측 클래스를 만들었습니다.

$myClass = new ClassWithFoo(); 
if ($instrumentationOn) { 
    $myClass = new GenericClassInstrumentor($myClass); 
} 

가 같은과 (동일하게 작동 할 $myClass->foo($bar)를 호출 :

<?php 

class GenericClassInstrumentor 
{ 
    private $instrumentedClass; 
    private $className; 

    public function __construct($instrumentedClass) 
    { 
     $this->instrumentedClass = $instrumentedClass; 
     $this->className = get_class($instrumentedClass); 
    } 

    public function __call($name, $arguments) 
    { 
     $start = microtime(true); 
     $result = call_user_func_array(array($this->instrumentedClass, $name), $arguments); 
     $end = microtime(true); 
     $duration = ($end - $start) * 1000; 

     // optionally log something here 
     return $result; 
    } 
} 

당신은 당신이 뭔가를 할 것, 거기에 기능 foo했다 $myClass 같은 클래스의 인스턴스를 가지고 말 @ircmaxell 대답과 같은 경우) $instrumentationOntrue 또는 false입니다. true이라면 여분의 타이밍 작업 만 수행하면됩니다.