2009-09-15 129 views
7

我希望能夠通過另一個函數來包裝PHP函數,但保留原來的名稱/參數列表不變。python裝飾器的PHP等價物?

例如:

function A() { 
    print "inside A()\n"; 
} 

function Wrap_A() { 
    print "Calling A()\n"; 
    A(); 
    print "Finished calling A()\n"; 
} 

// <--- Do some magic here (effectively "A = Wrap_A") 

A(); 

輸出:

Calling A() 
inside A() 
Finished calling A() 
+0

你Wrap_A的例子是有點誤導人誰不已經知道如何Python的裝飾器的工作,因爲你Wrap_A的實施顯式地引用A.一個裝飾的想法是,你可以裝飾任何函數,但在你的例子顯然不能使用'Wrap_A'來包裝其他一些函數'B'。你介意我是否編輯了你的問題,讓它更精確地表示裝飾是什麼功能? – 2014-01-05 15:11:37

回答

6

顯然runkit可能help you

此外,你可以隨時做到這一點的方式。把原來的樂趣放在一個類中,並將裝飾器放入擴展類中。實例化並去。

+0

謝謝'runkit'正是我一直在尋找。 – Fragsworth 2009-09-15 06:16:48

+1

你將如何使用它一樣容易,一般在蟒蛇 - 在這裏你添加裝飾只是函數定義以上(在.NET和Java見過類似的結構)。 – Michael 2012-04-24 11:32:11

1

也許你正在尋找call_user_func_array

function wrapA() { 
    $args = func_get_args(); 
    return call_user_func_array('A', $args); 
} 

因爲PHP 5.3,你甚至可以說:

return call_user_func_array('A', func_get_args()); 

編輯完你的問題,我會說,不,這是不可能的,但也有一些方法後,看到了這個問題:how to implement a decorator in PHP?

+0

這是不是在所有涉及到什麼我要找的。我編輯了我的問題以添加說明。 – Fragsworth 2009-09-15 06:02:02

1

你不能用PHP函數做到這一點。在其他動態語言中,例如Perl和Ruby,您可以重新定義以前定義的函數,但是當您嘗試這樣做時,PHP會引發致命錯誤。

在5.3中,你可以創建一個anonymous function並將其存儲在一個變量:

<?php 
    $my_function = function($args, ...) { ... }; 
    $copy_of_my_function = $my_function; 
    $my_function = function($arg, ...) { /* Do something with the copy */ }; 
?> 

或者,你可以使用傳統的裝飾圖案和/或工廠和工作帶班來代替。

1

這是我在php中使用python模擬裝飾器的方法。

function call_decorator ($decorator, $function, $args, $kwargs) { 

    // Call the decorator and pass the function to it 
    $decorator($function, $args, $kwargs); 
} 

function testing ($args, $kwargs) { 
    echo PHP_EOL . 'test 1234' . PHP_EOL; 
} 

function wrap_testing ($func, $args, $kwargs) { 

    // Before call on passed function 
    echo 'Before testing'; 

    // Call the passed function 
    $func($args, $kwargs); 

    // After call on passed function 
    echo 'After testing'; 
} 

// Run test 
call_decorator('wrap_testing', 'testing'); 

輸出:

Before testing 
testing 1234 
After testing 

使用這種實現,你也可以做這樣的事情有一個匿名函數:

// Run new test 
call_decorator('wrap_testing', function($args, $kwargs) { 
    echo PHP_EOL . 'Hello!' . PHP_EOL; 
}); 

輸出:

Before testing 
Hello! 
After testing 

並且最後你甚至可以做一些像這樣的事情,如果你這麼傾向。

// Run test 
call_decorator(function ($func, $args, $kwargs) { 
    echo 'Hello '; 
    $func($args, $kwargs); 
}, function($args, $kwargs) { 
    echo 'World!'; 
}); 

輸出:

Hello World! 

通過以上這種結構,可以將變量傳遞給內部函數或包裝,如果需要的話。下面是一個匿名的內部函數實現:

$test_val = 'I am accessible!'; 

call_decorator('wrap_testing', function($args, $kwargs){ 
    echo $args[0]; 
}, array($test_val)); 

它將工作完全一樣沒有一個匿名函數:

function test ($args, $kwargs) { 
    echo $kwargs['test']; 
} 

$test_var = 'Hello again!'; 

call_decorator('wrap_testing', 'test', array(), array('test' => $test_var)); 

最後,如果您需要修改任何包裝或內部變量wrappie,你只需要通過引用傳遞變量。

在不參考:

$test_var = 'testing this'; 
call_decorator(function($func, $args, $kwargs) { 
    $func($args, $kwargs); 
}, function($args, $kwargs) { 
    $args[0] = 'I changed!'; 
}, array($test_var)); 

輸出:

testing this 

參考:

$test_var = 'testing this'; 
call_decorator(function($func, $args, $kwargs) { 
    $func($args, $kwargs); 
}, function($args, $kwargs) { 
    $args[0] = 'I changed!'; 

// Reference the variable here 
}, array(&$test_var)); 

輸出:

I changed! 

這就是我的全部,現在,它是一個在很多情況下非常有用,你甚至可以多次包裝他們,如果你想。