2009-09-15 12 views
7

Voglio essere in grado di avvolgere una funzione PHP con un'altra funzione, ma lasciando intatto il suo nome originale/elenco parametri.equivalente PHP per un decoratore python?

Per esempio:

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

uscita:

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

Il tuo esempio di Wrap_A è un po 'fuorviante per qualcuno che non sa già come funziona il decoratore Python, dal momento che la tua implementazione di Wrap_A fa esplicito riferimento a A. L'idea di un decoratore è che puoi decorare qualsiasi funzione con esso, ma in il tuo esempio non puoi chiaramente usare 'Wrap_A' per racchiudere qualche altra funzione' B'. Ti dispiacerebbe se avessi modificato la tua domanda per renderla una rappresentazione più accurata di cosa sia la decorazione della funzione? –

risposta

6

Apparentemente runkit potrebbe help you.

Inoltre, puoi sempre farlo in modo OO. Metti il ​​divertimento originale in una classe e il decoratore in una classe estesa. Istanziare e andare.

+0

Grazie, 'runkit' è esattamente quello che stavo cercando. – Fragsworth

+1

Come lo useresti facilmente e genericamente come in python: qui aggiungi la decorazione appena sopra la definizione della funzione (costrutti simili visti in .NET e Java). – Michael

1

forse siete alla ricerca di call_user_func_array:

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

da PHP 5.3 Si potrebbe anche dire:

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

dopo aver modificato la tua domanda, direi, no, questo non è possibile, ma ci sono alcuni modi, vedi questa domanda: how to implement a decorator in PHP?

+0

Questo non è affatto relativo a ciò che sto cercando. Ho modificato la mia domanda per aggiungere chiarimenti. – Fragsworth

1

Non si può fare questo con funzioni in PHP . In altri linguaggi dinamici, come Perl e Ruby, è possibile ridefinire le funzioni definite in precedenza, ma PHP genera un errore fatale quando si tenta di farlo.

In 5.3, è possibile creare un anonymous function e memorizzarlo in una variabile:

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

In alternativa, è possibile utilizzare il modello tradizionale decoratore e/o di una fabbrica e il lavoro con le classi, invece.

1

Ecco il mio metodo di imitare decoratori da Python in 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'); 

uscita:

Before testing 
testing 1234 
After testing 

Con questa implementazione si può anche fare qualcosa di simile con una funzione anonima:

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

uscita:

Before testing 
Hello! 
After testing 

E infine si può anche fare un po ' cosa del genere, se sei così inclinato.

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

uscita:

Hello World! 

Con questa costruzione sopra, è possibile passare variabili per la funzione interna o involucro, se necessario.Ecco che l'implementazione di una funzione interna anonima:

$test_val = 'I am accessible!'; 

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

Funzionerà esattamente la stessa, senza una funzione anonima:

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

$test_var = 'Hello again!'; 

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

Infine, se è necessario modificare la variabile all'interno sia l'involucro o la wrappie, devi solo passare la variabile per riferimento.

Senza riferimento:

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

uscita:

testing this 

Con riferimento:

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

uscita:

I changed! 

Questo è tutto ciò che ho per ora, è abbastanza utile in molti casi, e puoi anche copiarli più volte se lo desideri.