wtorek, 29 stycznia 2013

Refleksje - uzyskanie tablicy argumentów

Jakiś czas temu spotkałem się w jakimś języku programowania z "agregacją" argumentów, nie pamiętam gdzie, ale wyglądało to mniej więcej tak:

function test( foo, bar ... )
    {

    foo; // 1

    bar; // [ 2, 3, 4, 5 ]

    }

test( 1, 2, 3, 4, 5 );
foo jest to typowy argument - nazwany, bar to wspomniany agregujący, który przechowuje wartości w tablicy. W PHP podobna sytuacja jest rozwiązana specjalnym zestawem funkcji:
function test( $foo )
    {

    $foo; // 1
    func_num_args(); // 5
    func_get_args(); // array( 1, 2, 3, 4, 5 ) 
    func_get_arg( 1 ); // 2

    }

test(1,2,3,4,5);
Jak widać func_get_args() zwraca tablicę indeksowaną numerycznie, a co jeśli chciałbym mieć w kluczach nazwy argumentów? Tutaj właśnie pomoże programowanie refleksyjne
function test( $foo )
    {

    $foo; // 1

    $ReflectionFunction = new ReflectionFunction( __FUNCTION__ ); // 1. tworzona jest refleksja aktualnej funkcji
    $param = $ReflectionFunction->getParameters();                // 2. z refleksji funkcji pobierana jest tablica refleksji parametrów
    $count = count( $param );                                     // 3. zapisuję liczbę parametrów
    $bar = array_combine(                                         // 8. wartości połączonej tablicy służą jako klucze dla kolejnych argumentów
        array_merge(                                              // 7. łączone są obie tablice
            array_map(                                            // 4. tablica parametrów jest mapowana
                function( $ReflectionParameter )
                    {
                    return $ReflectionParameter->name;            // 5. z parametru wyciągana jest tylko jej nazwa
                    },
                 $param ),
            range( $count, func_num_args() - $count ) ),          // 6. tworzona jest tablica z przyszłymi kluczami dla nienazwanych parametrów
        func_get_args() );

    $bar; // array( 'foo' => 1, 1 => 2, 2=> 3, 3 => 4, 4 => 5 ) 

    }

test( 1, 2, 3, 4, 5 );
Jest to złożone rozwiązanie, ale jednocześnie uniwersalne (niezależne od liczby argumentów nazwanych i nienazwanych), które mi się przydało.

Update 2013-01-31 23:00:
W dyskusji z bratem (który w przeciwieństwie do mnie jest na bieżąco z C++) wyszło że w C/C++ jest "agregacja" argumentów, nazywana zmienną liczbą argumentów
void fun( char *msg, ... );