Start · Sprachen · PHP · Referenz · runkit7_function_redefine

runkit7_function_redefine

Funktion

Ersetzt die Implementierung einer bestehenden PHP-Funktion zur Laufzeit durch neuen Code.

Kategorie: misc

Signatur

runkit7_function_redefine(string $function_name, string $argument_list, string $code, bool $return_by_ref = false, string $doc_comment = null, string $return_type = null, int $flags = 0): bool

Beschreibung

runkit7_function_redefine() gehört zur runkit7-PECL-Erweiterung und ermöglicht es, eine bereits definierte PHP-Funktion zur Laufzeit vollständig durch eine neue Implementierung zu ersetzen. Dabei bleibt der Funktionsname erhalten, während Parameterliste, Funktionskörper und optionale Metadaten (Docblock, Rückgabetyp) ausgetauscht werden.

Typische Einsatzgebiete sind das Mocking von Funktionen in Unit-Tests (z. B. wenn eine Funktion eine externe Abhängigkeit kapselt und nicht über Dependency-Injection austauschbar ist) sowie das temporäre Überschreiben von Verhalten in Testumgebungen. In Produktionssystemen sollte die Funktion generell vermieden werden, da sie den Code schwer nachvollziehbar und wartbar macht.

Der Parameter $argument_list wird als einfacher String übergeben (z. B. '$a, $b'), und der Funktionskörper ($code) ebenfalls als String mit PHP-Code ohne umschließende geschweifte Klammern. Dies ähnelt der Funktionsweise von create_function(), ist jedoch mächtiger, da eine bestehende Funktion ersetzt wird.

Wichtig: Die Erweiterung runkit7 muss installiert und in der php.ini aktiviert sein. Außerdem muss runkit.internal_override = On gesetzt sein, um interne PHP-Funktionen überschreiben zu können.

Parameter

Name Typ Default Beschreibung
$function_name Pflicht string Der Name der zu ersetzenden Funktion. Die Funktion muss bereits definiert sein.
$argument_list Pflicht string Die neue Parameterliste als String, z. B. '$a, $b = 10'. Leerer String, wenn keine Parameter gewünscht.
$code Pflicht string Der PHP-Quellcode der neuen Funktionsimplementierung als String, ohne umschließende geschweifte Klammern, z. B. 'return $a + $b;'.
$return_by_ref bool false Gibt an, ob die neue Funktion per Referenz zurückgeben soll (true) oder nicht (false).
$doc_comment string null Optionaler PHPDoc-Kommentar als String, der der neuen Funktion zugeordnet wird.
$return_type string null Optionaler Rückgabetyp als String (z. B. 'int', 'string'), der zur Funktionssignatur hinzugefügt wird.
$flags int 0 Optionale Flags, z. B. RUNKIT7_ACC_STATIC. In der Regel 0 für normale Funktionen.

Rückgabewert

Typ
bool
Beschreibung
Gibt true bei Erfolg zurück, false wenn die Funktion nicht gefunden wurde oder die Neudefinition fehlschlug.

Beispiele

Einfache Funktion zur Laufzeit ersetzen

<?php
// Ursprüngliche Funktion
function greet(string $name): string {
    return "Hallo, $name!";
}

echo greet('Welt') . PHP_EOL; // Hallo, Welt!

// Funktion zur Laufzeit ersetzen
runkit7_function_redefine(
    'greet',
    '$name',
    'return "Guten Tag, $name!";'
);

echo greet('Welt') . PHP_EOL; // Guten Tag, Welt!
Hallo, Welt! Guten Tag, Welt!

Funktion in Unit-Tests mocken

<?php
// Originale Hilfsfunktion, die eine externe API aufruft
function fetch_user_status(int $userId): string {
    // Würde normalerweise eine HTTP-Anfrage machen
    return 'online';
}

// Im Test: Funktion durch ein Mock ersetzen
runkit7_function_redefine(
    'fetch_user_status',
    '$userId',
    'return "offline";'
);

$status = fetch_user_status(42);
echo $status; // offline — kein echter HTTP-Call

// Assertion im Test
assert($status === 'offline', 'Mock-Status sollte offline sein');
offline

// Wichtig · Fallstricke

Achtung: runkit7_function_redefine() sollte niemals in Produktionscode eingesetzt werden. Das dynamische Ersetzen von Funktionen zur Laufzeit führt zu schwer nachvollziehbarem Verhalten und kann bei parallelen Requests zu Race-Conditions führen.

Um interne PHP-Funktionen (z. B. strlen, time) zu überschreiben, muss in der php.ini die Direktive runkit.internal_override = On gesetzt sein. Ohne diese Einstellung schlägt der Aufruf für Built-in-Funktionen fehl.

Der Funktionskörper wird als String ausgewertet — ähnlich wie bei eval(). Niemals Benutzereingaben ungeprüft in $code einfließen lassen, da dies eine kritische Code-Injection-Schwachstelle darstellt.

Als Alternative zum Mocking von Funktionen empfiehlt sich, wo möglich, eine Architektur mit Dependency Injection und Interfaces zu verwenden, da diese ohne PECL-Erweiterungen auskommt und testfreundlicher ist.