2009-09-15 8 views
7

Je veux être en mesure d'envelopper une fonction PHP par une autre fonction, mais en laissant son nom/liste de paramètres d'origine intacte.PHP équivalent pour un décorateur python?

Par exemple:

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(); 

Sortie:

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

Votre exemple de Wrap_A est un peu trompeur pour quelqu'un qui ne sait pas déjà comment le travail de Python décorateur, puisque votre implémentation de Wrap_A référence explicitement A. L'idée d'un décorateur est que vous pouvez décorer n'importe quelle fonction avec, mais Dans votre exemple, vous ne pouvez pas utiliser 'Wrap_A' pour envelopper une autre fonction' B'. Cela vous dérangerait-il si je modifiais votre question pour en faire une représentation plus précise de la fonction de décoration? –

Répondre

6

Apparemment, runkit pourrait help you.

Aussi, vous pouvez toujours le faire de la manière OO. Mettez le plaisir original dans une classe, et le décorateur dans une classe élargie. Instancier et partir.

+0

Merci, 'runkit' est exactement ce que je cherchais. – Fragsworth

+1

Comment l'utiliseriez-vous aussi facilement et génériquement que dans python - ici, vous ajoutez le décor juste au-dessus de la définition de la fonction (constructions similaires vues dans .NET et Java). – Michael

1

peut-être vous êtes à la recherche call_user_func_array:

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

depuis PHP 5.3 vous pourriez même dire:

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

Une fois que vous avez modifié votre question, je dirais que non, cela est impossible, mais il y a des façons, voir cette question: how to implement a decorator in PHP?

+0

Ce n'est pas du tout lié à ce que je cherche. J'ai édité ma question pour ajouter une clarification. – Fragsworth

1

Vous ne pouvez pas le faire avec des fonctions en PHP . Dans d'autres langages dynamiques, tels que Perl et Ruby, vous pouvez redéfinir les fonctions précédemment définies, mais PHP renvoie une erreur fatale lorsque vous tentez de le faire.

En 5.3, vous pouvez créer un anonymous function et le stocker dans une variable:

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

Vous pouvez également utiliser le modèle décorateur traditionnel et/ou d'une usine et de travailler avec des classes à la place.

1

Voici ma méthode pour imiter les décorateurs de python en php.

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'); 

Sortie:

Before testing 
testing 1234 
After testing 

Avec cette implémentation, vous pouvez aussi faire quelque chose comme ça avec une fonction anonyme:

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

Sortie:

Before testing 
Hello! 
After testing 

Enfin vous peut même faire quelques chose comme ça, si vous êtes si incliné.

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

Sortie:

Hello World! 

Avec cette construction ci-dessus, vous pouvez passer des variables à la fonction interne ou un emballage, le cas échéant.Voici que la mise en œuvre d'une fonction interne anonyme:

$test_val = 'I am accessible!'; 

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

Il fonctionnera exactement de la même sans une fonction anonyme:

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

$test_var = 'Hello again!'; 

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

Enfin, si vous avez besoin de modifier la variable à l'intérieur soit l'enveloppe ou la wrappie, il suffit de passer la variable par référence.

Sans référence:

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

Sortie:

testing this 

référence:

$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)); 

Sortie:

I changed! 

C'est tout ce que j'ai pour l'instant, c'est très utile dans beaucoup de cas, et vous pouvez même les emballer plusieurs fois si vous le souhaitez.

Questions connexes